Java - 基本概念与常识

lllllan ... 2022-3-16 Java
  • Java基础
About 7 min

# 一、 Java语言的特点

  1. 简单性:丢弃了C++中少用、难懂的特性,例如操作符重载、多继承、指针、内存管理等,不用手动管理对象的生命周期。
  2. 面向对象:封装,继承,多态
  3. 平台无关性:一次编译到处运行
  4. 解释执行:编译成字节码文件,java解释器对字节码进行解释执行
  5. 多线程
  6. 分布式(强大、易于使用的联网能力)
  7. 高性能(相对其他高级语言,JIT (opens new window)的发展)
  8. 健壮性(强类型机制、异常处理、垃圾回收机制)
  9. 安全性(安全机制以防止恶意代码的攻击)

# 1.1 编译与解释并存

由 Java 编写的程序需要先经过 编译 步骤,生成字节码(.class 文件),这种字节码必须由 Java 解释器来 解释执行

# 1.2 跨平台

java 代码被编译成字节码文件,字节码是平台无关的,是面向 JVM 编写的。

JVM 的接口是向下与硬件有关的,在不同平台上有不同的指令系统,才能支持字节码文件在不同的操作系统下解释执行,从而实现 Java 的跨平台性也就是可移植性

# 二、JVM & JDK & JRE

  1. Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。
  2. JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。
  3. JDK 是 Java Development Kit 缩写,它是功能齐全的 Java SDK。它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。

JDK > JRE > JVM

浅谈JDK、JRE、JVM区别与联系 (opens new window)

  1. JVM不能单独执行class
  2. JRE = JVM + lib(jvm工作需要的类库)。可以执行class
  3. JDK包含JRE。可以开发、编译、执行

img

# 2.1 Oracle JDK & OpenJDK (不懂)

Java基础常见知识&面试题总结(上) | JavaGuide (opens new window)

# 三、字节码及优点

JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。

  • Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。
  • 由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。

Java程序转变为机器代码的过程

为什么

参考: 什么是字节码?采用字节码的最大好处是什么? (opens new window)

解释型语言

  • 优点:程序运行时才进行翻译,容易维护 、方便快速部署、不用停机维护。
  • 缺点:每次运行都要解释一遍,性能较低

编译型语言

优点:编译器会对程序代码进行优化,并且只需要进行一次编译、效率较高

缺点:修个当个功能需要重新编译整个模块,不同的运行环境需要编译不同的机器码才能执行

采用字节码:

  1. 先通过编译器对程序进行编译,会有一轮优化,能够一定程度上提高性能
  2. 字节码面向虚拟机, 可由不同平台的虚拟机直接解释执行,不需要重新编译,实现可移植的特点

# 四、Java 是值传递

# 4.1 值传递 & 引用传递

程序设计语言将实参传递给方法(或函数)的方式分为两种:

  • 值传递 :方法接收的是实参值的拷贝,会创建副本。
  • 引用传递 :方法接收的直接是实参所引用的对象在堆中的地址,不会创建副本,对形参的修改将影响到实参。

很多程序设计语言(比如 C++、 Pascal )提供了两种参数传递的方式,不过,在 Java 中只有值传递。

# 4.2 修改基本数据类型

class Solution {

    public void swap(int a, int b) {
        System.out.println("执行交换函数,将a、b的值对换");
        int tmp = a;
        a = b;
        b = tmp;
    }

    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        System.out.println("执行前:a = " + a + ", b = " + b);

        new Solution().swap(a, b);

        System.out.println("执行后:a = " + a + ", b = " + b);
    }
}

-----------------------------------------------------------------
执行前:a = 1, b = 2
执行交换函数,将a、b的值对换
执行后:a = 1, b = 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • a和b只是从num1和num2复制得到了值,怎么操作都不会产生影响

# 4.3 修改引用类型中的值

class Solution {

    public void print(int[] array) {
        for (int num : array) {
            System.out.print(num + " ");
        }
        System.out.println("");
    }

    public void swap(int[] array) {
        System.out.println("执行交换函数,将数组首尾两数对换");
        int tmp = array[0];
        array[0] = array[array.length - 1];
        array[array.length - 1] = tmp;
    }

    public void change(int[] array) {
        System.out.println("创建新的数组");
        array = new int[]{4, 5, 6};
    }

    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3};
        System.out.print("原数组:");
        new Solution().print(arr);

        new Solution().swap(arr);
        System.out.print("交换后数组:");
        new Solution().print(arr);

        new Solution().change(arr);
        System.out.print("创建后数组:");
        new Solution().print(arr);
    }
}

------------------------------------------------------------------
原数组:1 2 3 
执行交换函数,将数组首尾两数对换
交换后数组:3 2 1 
创建新的数组
创建后数组:3 2 1 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • 函数中的int[] arr 只是对数组 引用 的一个拷贝
    • 对这个引用指向的数组对象就行内容修改,两个引用都能查看到
    • 但是对这个 新的引用 创建新的数组,也不会影响原来的 数组引用 指向的数组对象。

引用数据类型参数1

# 4.4 修改引用类型的对象

class Solution {

    static class Student {
        private String name;

        public Student(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        private void setName(String name) {
            this.name = name;
        }
    }

    static void swapName(Student s1, Student s2) {
        System.out.println("直接交换两人的姓名");
        String name = s1.getName();
        s1.setName(s2.getName());
        s2.setName(name);
    }

    static void swapStudent(Student s1, Student s2) {
        System.out.println("交换两个对象");
        Student tmp = s1;
        s1 = s2;
        s2 = tmp;
    }

    public static void main(String[] args) {
        Student xz = new Student("xiaoZhang");
        Student xl = new Student("xiaoLi");
        System.out.println("xz:" + xz.getName() + ", xl: " + xl.getName());

        swapName(xz, xl);
        System.out.println("xz:" + xz.getName() + ", xl: " + xl.getName());

        swapStudent(xz, xl);
        System.out.println("xz:" + xz.getName() + ", xl: " + xl.getName());
    }
}

---------------------------------------------------------------------------------
xz:xiaoZhang, xl: xiaoLi
直接交换两人的姓名
xz:xiaoLi, xl: xiaoZhang
交换两个对象
xz:xiaoLi, xl: xiaoZhang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

引用数据类型参数2

# 总结

Java 中将实参传递给方法(或函数)的方式是 值传递

  • 如果参数是基本类型的话,很简单,传递的就是基本类型的字面量值的拷贝,会创建副本。
  • 如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,同样也会创建副本。

# 五、程序、进程和线程

简单来说, 一个进程就是一个执行中的程序 ,它在计算 机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空 间,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存 中。 线程是进程划分成的更小的运行单位 。线程和进程最大的不同在于基本上各进程是独立的,而 各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系 统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同 时执行一个以上的程序段。

Last update: 2022年4月11日 23:41
Contributors: lllllan