记录自己快速熟悉Java基础的历程

一、Java概述

1.1 什么是Java

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

1.2 Java三大版本

  1. Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
  2. Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
  3. Java ME(J2ME,Java 2 Platform Micro Edition,微型版)

1.3 JVM、JRE和JDK的关系

  1. JVM
    Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。
  2. JRE
    Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包

    只运行java程序的话,只需要安装JRE

  3. JDK
    Java Development Kit是提供给Java开发人员使用的,其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等

    Java开发环境,就安装JDK,包含JRE等

1.4 Java语言有哪些特点

  1. 简单易学(Java的语法与C/C++很接近)
  2. 面向对象(封装,继承,多态)
  3. 跨平台(.java文件->javac->.class->java通过JVM运行)
  4. 解释型语言
  5. Java有自动内存管理机制,不需要程序员手动释放无用内存

1.5 什么是字节码?字节码的好处是什么?

  1. 字节码:
    Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。
  2. 采用字节码的好处:
    Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

1.6 Java程序执行流程

二、Java基础

2.1 输入输出、数据类型

2.1.1 Hello world

1
2
3
4
5
6
//Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
  1. 源文件名与类名相同
  2. 每个类只能有一个main(类的入口方法)
  3. 使用//进行注释

2.1.2 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Variable.java 
public class Variable {
public static void main(String[] args) {
byte num0=127;
short num1=200;
int num2=100;
long num3=123123123123123123L;
float num4=3.14f;
double num5=3.14123123123;
char ch='a';
boolean flag=true;
System.out.println("字节类型num0="+num0);
System.out.println("短整型num1="+num1);
System.out.println("整型num2="+num2);
System.out.println("长整型num3="+num3);
System.out.println("浮点型num4="+num4);
System.out.println("双精度浮点型num5="+num5);
System.out.println("字符ch="+ch);
System.out.println("布尔值flag="+flag);
}
}
  • 数据类型的转换关系
  1. byte->short->int->long->float->double(精度链/范围链)
  2. 上面的链反向需强制类型转换
  3. 自动类型转换
    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
    //Change_byte.java
    public class Change_byte {
    public static void main(String[] args) {
    int aInt = 20;
    long bLong = 50L;
    double cDouble = 4.8;

    //低优先级类型数据 + 高优先级类型数据 ——> 结果会自动转换为高优先级数据
    long sum = aInt + bLong;

    //long -> int 需要强制类型转换
    int d = (int) bLong;
    //double -> int 需要强制类型转换
    int e = (int) cDouble;

    System.out.println("自动类型转换 int—>long: " + sum);
    System.out.println("强制类型转换 long—>int: " + d);
    System.out.println("强制类型转换 double—>int: " + e);
    System.out.println();

    //int 和 byte 转换
    byte fByte = (byte) aInt; //高转低,强转
    int gInt = fByte; //低转高,自动
    System.out.println("高转低-强转,int->byte: " + fByte);
    System.out.println("低转高-自动,byte->int: " + gInt);
    System.out.println();

    //int 和 char 转换
    char hChar = 'a';
    int iInt = hChar;
    char j = (char) iInt;
    System.out.println("低转高-自动,char->int: " + iInt);
    System.out.println("高转低-强转,int->char: " + j);
    System.out.println();

    //byte 和 char 互转
    byte m = (byte) hChar;
    char n = (char) m;
    System.out.println("char->byte,强转: " + m);
    System.out.println("byte->char,强转: " + n);
    }
    }

2.1.3 引用数据类型

引用数据类型的内存分布,可以类比C/C++中的指针

  • 数组

    一维数组

    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
    //Bubble_sort.java  
    public class Bubble_sort {
    public static void main(String[] args) {
    int n=20;
    int arr[]=new int[n];
    Random numList = new Random();
    for (int i = 0; i <n; i++) {
    arr[i]= numList.nextInt(100);
    }
    int temp=0;
    for (int i = 0; i< arr.length-1; i++){
    for (int j=0;j<arr.length-1-i;j++){
    if (arr[j]>arr[j+1]){
    temp=arr[j];
    arr[j]=arr[j+1];
    arr[j+1]=temp;
    }
    }
    System.out.println("第"+i+"轮");
    for (int k=0;k<arr.length;k++){
    System.out.print(arr[k]+"\t");
    }
    System.out.println();
    }
    }
    }

    二维数组

    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
    //MiGong.java    迷宫
    public class MiGong {
    public static void main(String[] args) {
    int arr[][] = new int[10][10];
    for (int i=0;i<10;i++){
    arr[0][i]=1;
    arr[arr.length-1][i]=1;
    }
    for (int i=0;i<10;i++){
    arr[i][0]=1;
    arr[i][arr.length-1]=1;
    }
    arr[3][1]=1;
    arr[2][2]=1;
    Tools tools=new Tools();
    tools.FindWay(arr,2,1);

    for (int i=0;i<arr.length;i++){
    for (int j=0;j<arr[i].length;j++){
    System.out.print(arr[i][j]+"\t");
    }
    System.out.println();
    }

    }
    }
    class Tools{
    public boolean FindWay(int arr[][],int start_i,int start_j){
    if (arr[arr.length-2][arr.length-2]==2){
    return true;
    }else {
    if (arr[start_i][start_j]==0){
    arr[start_i][start_j]=2;
    if (FindWay(arr,start_i+1,start_j))
    return true;
    else if (FindWay(arr,start_i,start_j+1))
    return true;
    else if (FindWay(arr,start_i-1,start_j))
    return true;
    else if (FindWay(arr,start_i,start_j-1))
    return true;
    else{
    arr[start_i][start_j]=3;
    return false; }
    }else {
    return false;
    }
    }
    }
    }
  • 接口

    后面讲

2.1.4 输入

  • 导入包import java.util.Scanner;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import java.util.Scanner;
    //Print.java
    public class Print {
    public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    //接收一个int类型的值并进行输出
    System.out.println(scanner.nextInt());
    System.out.println(scanner.nextDouble());
    System.out.println(scanner.nextBoolean());
    }
    }

2.2 运算符

2.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
//arithmetic.java  
public class arithmetic {
public static void main(String[] args) {
int a = 10;
int b = 5;

System.out.println(a + b);//15
System.out.println(a - b);//5
System.out.println(a * b);//50
System.out.println(a / b);//2
System.out.println(a % b);//0

b = 3;
System.out.println(a + b);//13
System.out.println(a - b);//7
System.out.println(a * b);//30
System.out.println(a / b);//3 类型导致的
System.out.println(a % b);//1

System.out.println(10+200);//210
System.out.println("abc"+"zxy");//abczxy
System.out.println(100+"2ab");//1002ab
System.out.println("2ab"+100);//2ab100
}
}

2.2.2 关系运算符

1
2
3
4
5
6
7
8
9
10
11
12
//relationship.java  
public class relationship {
public static void main(String[] args) {
int a = 10, b = 20;
System.out.println(a == b); // false
System.out.println(a != b); // true
System.out.println(a > b); // false
System.out.println(a < b); // true
System.out.println(a >= b); // false
System.out.println(a <= b); // true
}
}

2.2.3 位运算符

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
//Bitwise_operators.java  
public class Bitwise_operators {
public static void main(String[] args) {
int a = 60, b = 13;
System.out.println("a 的二进制:" + Integer.toBinaryString(a)); // 111100
System.out.println("b 的二进制:" + Integer.toBinaryString(b)); // 1101

int c = a & b;
System.out.println("a & b:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = a | b;
System.out.println("a | b:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = a ^ b;
System.out.println("a ^ b:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = ~a;
System.out.println("~a:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = a << 2;
System.out.println("a << 2:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = a >> 2;
System.out.println("a >> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));

c = a >>> 2;
System.out.println("a >>> 2:" + c + ",二进制是:" + Integer.toBinaryString(c));
}
}

2.2.4 二进制

  1. 二进制的高位为符号位(0表示整数,1表示负数)
  2. 正数的原码、补码、反码都一样(三码合一)
  3. 负数的反码=原码符号位不变,其他位取反
  4. 负数的补码=反码+1
  5. 负数的反码=补码-1
  6. 0的反码和补码都是0
  7. 计算机在运行时,都是以补码形式运算
  8. 结果看原码
    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
    import java.util.Scanner;       //导入类

    public class Input {
    public static void main(String[] args) {
    int a=2,b=3;
    //a的原码、补码、反码:00000000 00000000 00000000 00000010
    //b的原码、补码、反码:00000000 00000000 00000000 00000011
    //-----------------------------------------------------
    // 00000000 00000000 00000000 00000010
    //且为正数,故值为2

    System.out.println(a&b);//2
    //-a的原码、补码、反码:10000000 00000000 00000000 00000010
    //-a的反码:11111111 11111111 11111111 11111101
    //-a的补码:11111111 11111111 11111111 11111110
    //~-a的补码:00000000 00000000 00000000 00000001
    //符号为0正数,结果为1
    System.out.println(~-a);//1

    //a的原码、11111111 11111111 11111111 11111101
    //~a的反码:11111111 11111111 11111111 11111100
    //~a的原码:10000000 00000000 00000000 00000011
    //符号位1负数,结果为-3
    System.out.println(~a);//-3
    }
    }

2.2.5 逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
//Logical.java  
public class Logical {
public static void main(String[] args) {
int num1=10;
int num2=5;
int num3=20;
System.out.println(num1<num2&&num1<num3);
//false && true = false

System.out.println(num1>num2||num1<num3);
//true || true = true
}
}

2.2.6 三元运算符

1
2
3
4
5
6
7
8
9
//Ternary.java  
public class Ternary {
public static void main(String[] args) {
int num1=100;
int num2=200;
int num3;
System.out.println(num1>num2?num1:num2);
}
}

2.3 流程控制

2.3.1 if-else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.Scanner;  

//If_else.java
public class If_else {
public static void main(String[] args) {
int n;
Scanner scanner = new Scanner(System.in);
n=scanner.nextInt();
if(n%2==0){
System.out.println("偶数");
}else{
System.out.println("奇数");
}
}
}

2.3.2 if-elseif-else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;
//If_elseif_else.java
public class If_elseif_else {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
double score=scanner.nextDouble();
if (score>=0&&score<=100){
if (score>=90)
System.out.println("A级");
else if (score>=80&&score<=89)
System.out.println("B级");
else if (score>=70&&score<=79)
System.out.println("C级");
else if (score>=60&&score<=69)
System.out.println("D级");
else System.out.println("不及格");
}else
System.out.println("输入有误!");
}
}

2.3.3 switch

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
import java.util.Scanner;  
//Switch_.java
public class Switch_ {
public static void main(String[] args) {
int n;
Scanner scanner = new Scanner(System.in);
n=scanner.nextInt();
switch (n){
case 1:
System.out.println("星期一");
break; case 2:
System.out.println("星期二");
break; case 3:
System.out.println("星期三");
break; case 4:
System.out.println("星期四");
break; case 5:
System.out.println("星期五");
break; case 6:
System.out.println("星期六");
break; case 7:
System.out.println("星期日");
break; default:
System.out.println("输入错误");
}
}
}

2.3.4 for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;  
//pyramid.java 空心金字塔
public class pyramid {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
for (int i = 1; i <= n; i++) {
for (int k = 1; k <=n-i ; k++) {
System.out.print(" ");
}
for (int j = 1;j <= 2*i-1; j++) {
if(j==1||j==2*i-1||i==n)
System.out.print("*");
else
System.out.print(" ");
}
System.out.println();
}
}
}

2.3.5 while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//While.java  
public class While {
public static void main(String[] args) {
int n=10;
//先减减再使用
//while先判断再运行
while ((--n)>=0){
System.out.println("i = " + n);
}
n=10;
System.out.println("==================");
//先使用再减减
while ((n--)>=0){
System.out.println("i = " + n);
}
}
}

2.3.6 do_while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Do_while.java  
public class Do_while {
public static void main(String[] args) {
int n=10;
do {
System.out.println(n);
n--;
}while (n>0);
System.out.println("==================");
n=0;
//先执行再判断
do {
System.out.println(n);
n--;
}while (n>0);
}
}

2.4 类与对象(OOP)

所有类均是Object的子类
状态+行为+标识=对象

2.4.1 属性

2.4.1.1 类成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Object_test.java  
public class Object_test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name="小花";
cat.age=3;
cat.color="白色";
cat.Info();
}
}
class Cat{
//类属性属性
String name;
int age;
String color;
//类方法
public void Info(){
System.out.println("name:"+this.name+" age:"+this.age+" color:"+this.color);
}
}

2.4.1.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//Object_test.java  
public class Object_test {
public static void main(String[] args) {
Cat cat = new Cat("小花",2,"黄色");
cat.Info();
}
}
class Cat{
//类属性
String name;
int age;
String color;
//无参构造器(默认),方法重载时,默认的将消失,如需要,自己申明
public Cat(){
//this(参数列表),即在自身中调用构造方法
//1.只能在构造器中使用
//2.如果要使用,代码必须放在构造器的第一条语句
this("小白",3,"黑色");
}
//有参构造器
public Cat(String name,int age,String color){
//this就是指对象本身,谁调用就是谁,只能在类内部使用

//this可以用于区分属性和局部变量
this.name=name;
this.age=age;
this.color=color;
//this可以访问本类的属性、方法、构造器
this.Info();
}
//类方法
public void Info(){
System.out.println("name:"+this.name+" age:"+this.age+" color:"+this.color);
}
}

//反汇编字节码文件
//-c 反汇编
//-v 输出附加信息
//-p 显示所有类和成员
//javap -c -v 文件名.class(可以除去后缀)

2.4.1.3 访问修饰符

成员变量和成员方法均可被修饰

2.4.2 重载

1.方法名必须相同
2.参数类型不同或者个数不同

2.4.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
//overloaded.java  
public class overloaded {
public static void main(String[] args) {
overload overload = new overload();
System.out.println(overload.calc(1,2));
System.out.println(overload.calc(1,2,3));
System.out.println(overload.calc(1.0,2.0));
System.out.println(overload.calc(1.0,2.0,3.0));
}
}
class overload{
//方法重载
/*
* 1.方法名必须相同
* 2.参数类型不同或者个数不同
* */ public int calc(int a,int b)
{
return a+b;
}
public int calc(int a,int b,int c)
{
return a+b+c;
}
public double calc(double a,double b)
{
return a+b;
}
public double calc(double a,double b,double c)
{
return a+b+c;
}
}

2.4.2.2 可变参数

接收可变参数个数的方法
1.参数可以是任意个>=0
2.本质其实就是数组
3.形参列表中,可变参数必须在最后
4.一个方法中,只能有一个可变参数

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
//Variadics.java  
public class Variadics {
public static void main(String[] args) {
Method method = new Method();
System.out.println(method.sum(1,2,3,4,5,6,7,8,9,10));
System.out.println(method.sum(1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.0));
}
}
class Method{
//可变参数接收
public int sum(int... args){
int sum_all=0;
for(int i=0;i<args.length;i++){
sum_all+=args[i];
}
return sum_all;
}
//方法重载
public double sum(double... args){
double sum_all=0;
for(int i=0;i<args.length;i++){
sum_all+=args[i];
}
return sum_all;
}
}

2.4.3 String类

2.4.3.1 String类的介绍

  1. String 类是final的,意味着它不能被子类继承
  2. String 类实现了 Serializable 接口,意味着它可以序列化
  3. String 类实现了 Comparable 接口,意味着最好不要用==来比较两个字符串是否相等,而应该用 equals() 方法

2.4.3.2 hashCode 方法

每一个字符串都会有一个 hash 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//String类的hashcode方法实现
public int hashCode() {
//首先检查是否已经计算过哈希码
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}

2.4.3.3 substring 方法

用来截取字符串

1
2
3
4
5
6
7
8
9
10
//String_01.java  
public class String_01 {
public static void main(String[] args) {
String str = "Hello, world!";
String subStr = str.substring(7, 12);
// 从第7个字符(包括)提取到第12个字符(不包括)
System.out.println(subStr); // 输出 "world"
System.out.println(str.hashCode());
}
}

2.4.3.4 indexOf 方法

indexOf 方法用于查找一个子字符串在原字符串中第一次出现的位置

1
2
3
4
5
6
7
//String_01.java  
public class String_01 {
public static void main(String[] args) {
String str="hello world";
System.out.println(str.indexOf("world"));
}
}

2.4.3.5 引用数据类型的拷贝

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
//Person.java  
public class Person {
public static void main(String[] args) {
Person_1 person = new Person_1();
person.name = "张三";
person.age = 18;
My_Tools my_tools = new My_Tools();
//传过去的是引用
Person_1 person1=my_tools.Copy_Object(person);
System.out.println("对象1的hash值="+person.hashCode());
System.out.println("对象2的hash值="+person1.hashCode());
if (person.hashCode()==person1.hashCode())
System.out.println("相同");
else
System.out.println("不同");
}
}

class Person_1{
String name;
int age;
}

class My_Tools{
//拷贝对象
public Person_1 Copy_Object(Person_1 ob j)
{
Person_1 person_1 = new Person_1();
person_1.name = obj.name;
person_1.age=obj.age;
return person_1;
}
}

2.4.4 包

在 Java 中,使用package来解决名字冲突
Java中的包:如何创建、导入和使用 package 来优化代码结构

例如:
小明的Person类存放在包ming下面,因此,完整类名是ming.Person
小红的Person类存放在包hong下面,因此,完整类名是hong.Person
小军的Arrays类存放在包mr.jun下面,因此,完整类名是mr.jun.Arrays
JDK 的Arrays类存放在包java.util下面,因此,完整类名是java.util.Arrays
在定义class的时候,我们需要在第一行声明这个class属于哪个包。

Java中常用的包

  1. java.lang.* //默认使用的包(默认引入,不需要手动引入)
  2. java.util.* //常用工具需要的包
  3. java.net.* //网络编程需要的包
  4. java.awt.* //界面开发需要的包
    import xxxx(包名),可以*通配导入,也可以具体类导入(推荐)

2.4.5 封装

将方法封装到类内部,根据需要进行过滤验证,保证安全性
数据被保护在类的内部,尽可能地隐藏内部的实现细节,只保留一些对外接口使之与外部发生联系。

2.4.5.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
43
44
45
46
47
48
49
//encapsulation.java  
public class encapsulation {
public static void main(String[] args)
{
Person_11 person_11 = new Person_11();
person_11.setName("张三");
person_11.setAge(18);
person_11.setSalary(10000);
person_11.Info();
}
}
class Person_11 {
private String name;
private int age;
private double salary;

public String getName() {
return name;
}

public void setName(String name) {
if (name.length()>=0&&name.length()<=20)
this.name = name;
else
System.out.println("名字长度不符合要求");
}

public int getAge() {
return age;
}

public void setAge(int age) {
if (age>=0&&age<=150)
this.age = age;
else
System.out.println("年龄不符合要求");
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}
public void Info(){
System.out.println("姓名:"+this.name+" 年龄:"+this.age+" 薪水:"+this.salary);
}
}

2.4.5.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
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
52
53
54
55
56
57
58
59
//encapsulation.java  
public class encapsulation {
public static void main(String[] args)
{
Person_11 person_11 = new Person_11();
person_11.setName("张三");
person_11.setAge(18);
person_11.setSalary(10000);
person_11.Info();
System.out.println("==========================");
Person_11 person_12 = new Person_11("李四",19,20000);
person_12.Info();
}
}
class Person_11 {
private String name;
private int age;
private double salary;


public Person_11()
{}
public Person_11(String name,int age,double salary){
this.setName(name);
this.setAge(age);
this.setSalary(salary);
}

public String getName() {
return name;
}

public void setName(String name) {
if (name.length()>=0&&name.length()<=20)
this.name = name;
else System.out.println("名字长度不符合要求");
}

public int getAge() {
return age;
}

public void setAge(int age) {
if (age>=0&&age<=150)
this.age = age;
else System.out.println("年龄不符合要求");
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}
public void Info(){
System.out.println("姓名:"+this.name+" 年龄:"+this.age+" 薪水:"+this.salary);
}
}

2.4.6 继承

解决多类情况下的代码复用问题
在 Java 语言中继承就是子类继承父类的属性和方法,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的方法

  1. 上图继承关系可以递归下去
  2. Java中继承机制是单继承,即子类只能继承一个父类
  3. 私有的属性和方法不能在子类直接访问,但是可以间接操作
    什么时候适合使用继承?

    什么是什么的关系才能用

2.4.6.1 简单的继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//inherit.java  
public class inherit {
public static void main(String[] args) {
Student student = new Student();
student.name="张三";
student.age=18;
student.school="北京大学";
student.study();
}
}
//父类
class Person_111{
public String name;
public int age;
}
//子类
class Student extends Person_111{
public String school;
public void study(){
System.out.println(name+"在"+school+"学习");
}
}

2.4.6.2 继承细节

2.4.6.2.1 私有属性、方法相关

父类写get方法,来获取父类的私有属性内容
父类写call方法,来间接调用父类的私有方法

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
//inherit.java  
public class inherit {
public static void main(String[] args) {
Student student = new Student("清华大学");
student.age=18;
student.setName("李四");
student.study();
//调用父类的接口方法
student.CallPrint();
}
}
//父类
class Person_111{
private String name;
public int age;

public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
private void Print(){
System.out.println("姓名:"+name+"\t年龄:"+age);
}
public void CallPrint(){
Print();
}
}
//子类
class Student extends Person_111{
public String school;

public Student(){}
public Student(String school){
this.school=school;
}
public void study(){
System.out.println(super.getName()+"在"+school+"学习");
}
}
2.4.6.2.2 初始化相关

子类在初始化时(即:创建对象时(调用构造方法时)),默认调用父类的无参构造器,即默认在子类的构造方法中阴藏写着super();


如果父类没有无参构造器,则必须在子类的构造方法中用super(实参)指定使用父类的哪个构造器,否则报错

super在使用时,必须放在构造器的第一行,且调用一直追溯到Object类
(俗称:先有爸爸后有儿)
super()与this()不可共存

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
//inherit.java  
public class inherit {
public static void main(String[] args) {
Student student = new Student();
/*输出
父类Person_111()无参构造器被调用。。。
子类Student()无参构造器被调用。。。
*/
}
}
//父类
class Person_111{
private String name;
public int age;

public Person_111() {
System.out.println("父类Person_111()无参构造器被调用。。。");
}

public Person_111(String name, int age) {
this.name = name;
this.age = age;
}
}
//子类
class Student extends Person_111{
public String school;

public Student(){
System.out.println("子类Student()无参构造器被调用。。。");
}
public Student(String school){
this.school=school;
}
}
2.4.6.2.3 查找关系相关

场景:子类继承了父类,但是子类的属性和父类的相同,那调用使用的是哪一个呢?

  1. 首先查看子类是否有该属性或者方法
    如果有且可以访问,则返回
    如果没有则继续向上查找,以此类推
    如果查找到一个则返回并终止查询,如果查找过程中出错也终止
  2. 如果直接使用成员或者this.成员(二者等价),依旧同上规则查找。
  3. 如果是super.成员,则直接跳过子类去父类查找
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    //Call_Relationship.java  
    public class Call_Relationship {
    public static void main(String[] args) {
    Son son = new Son();
    System.out.println(son.name);
    System.out.println(son.age);
    }
    }
    class GrandFather {
    String name="爷爷";
    String habby="喝酒";
    }
    class Father extends GrandFather {
    String name="爸爸";
    int age=50;
    }
    class Son extends Father {
    String name="儿子";
    }
2.4.6.2.4 this和super的比较

2.4.6.3 方法重写

子类有一个方法和父类的某个方法的名称、返回类型、参数一样,即子类的方法覆盖了父类的方法,称为子类重写了父类的方法
1.子类返回类型和父类返回类型一样
2.子类返回类型是父类返回类型的子类
3.子类不能缩小父类成员的访问权限
public > protected > default > private

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
52
53
//override.java  
public class override {
public static void main(String[] args) {
B b = new B();
//简单关系重写
b.eat();
//复杂关系重写
//String类是Object的子类
System.out.println(b.m1());
//权限缩小
//public > protected > default > private
b.m2();
}
}

class A{
public String name;
public int age;

public A() {}

public A(String name, int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("A eat");
}
public Object m1(){
return null;
}
void m2(){
System.out.println("A m2");
}
}
class B extends A{
public String color;
public B() {}
public B(String color, String name, int age){
super(name,age);
this.color = color;
}
//重写父类的eat方法
public void eat(){
System.out.println("B eat");
}
public String m1(){
return null;
}
protected void m2(){
System.out.println("B m2");
}
}
2.4.6.3.1 重载和重写的比较

2.4.7 多态

解决多类情况下的代码复用问题和减低维护成本

  1. 方法的多态,类似重载和重写去理解
  2. 类的多态,重点!!!难点!!!
  • 多态的前提:子类继承父类、父类引用指向子类的对象、子类重写父类的方法
  • 一个对象的编译类型和运行类型可以不一致,也可一样
    Animal animal = new Dog();animal =new Cat();
    当编译时,animal 的编译类型就是Animal,而指向的是Dog子类对象
    当运行时,animal 可以重新改变指向到Cat子类对象
  • 多态的向上转型
    Object obj = new Dog();就是例子,Dog是Object的子类,创建对象时,obj指向了子类Dog,即可以理解为Dog类向上转型(类型),但运行时是在Dog类
  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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    //Polymorphism.java  
    public class Polymorphism {
    public static void main(String[] args) {
    //编译类型是Animal,运行类型是Dogss
    Animal animal = new Dogss("旺财");//这里是向上转型
    Food food = new Bone("骨头");
    Persons person = new Persons("张三");//这里是编译型和运行型一样
    person.feed(animal,food);
    System.out.println("====================");
    //编译类型是Animal,运行类型是Catss
    Animal animal1=new Catss("汤姆");
    Food food1=new Fish("三文鱼");
    person.feed(animal1,food1);
    System.out.println("====================");
    // animal.sleep();
    //报错(编译报错),不能调用子类的方法,因不是重写的方法
    System.out.println("====================");
    //子类重写父类方法就可以调用,但是子类自己写的方法不能调用
    animal.eat();//运行调用,即运行态
    //子类重写的方法,运行时就调用重写的,未重写的就调用父类的
    }
    }
    //食物类
    class Food{
    private String name;

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

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }
    class Fish extends Food{
    public Fish(String name) {
    super(name);
    }
    }
    class Bone extends Food{
    public Bone(String name) {
    super(name);
    }
    }
    //动物类
    class Animal{
    private String name;

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

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    public void eat(){
    System.out.println(getName()+"父类正在吃饭");
    }

    }
    class Dogss extends Animal{
    public Dogss(String name) {
    super(name);
    }
    public void sleep(){
    System.out.println(getName()+"正在睡觉");
    }
    public void eat(){
    System.out.println(getName()+"子类正在吃饭");
    }
    }
    class Catss extends Animal{
    public Catss(String name) {
    super(name);
    }
    }

    //主人
    class Persons{
    private String name;

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

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    //如果不使用多态,形参列表一直在变,即多一个动物就要重载一次,代码冗余度高
    public void feed(Animal animal,Food food){
    System.out.println(this.name+"喂"+animal.getName()+"吃"+food.getName());
    }
    }

2.4.7.1 向下转型

子类类型 引用名=(子类类型)父类引用;

  1. 要求原父类的引用必须指向的是当前目标类型的对象
  2. 只能强转父类的引用,不能强转父类的对象(对象在堆中,引用在栈中)
  3. 向下转型后可以访问子类的成员了(上面的例子无法访问)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //上述基础上转类型,即可调用子类的特有方法
    //条件1
    Animal animal = new Dogss("旺财");//这里是向上转型
    Dogss dogss = (Dogss) animal; //这里是向下转型
    ((Dogss) animal).sleep();
    System.out.println("====================");
    //Catss catss = (Catss) animal;//报错,意思就说想把狗变成猫

    //条件2
    Animal animal2 = new Animal("山猪");
    Dogss dogss1 = (Dogss) animal2; //报错,原理其实是上面的狗变猫

2.4.7.2 instanceof

判断对象的运行类型是XX或者XX的子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Use_Instanceof.java
public class Use_Instanceof {
public static void main(String[] args) {
DD dd = new DD();
//instanceof用于判断对象的运行类型是否是某类或者某类的子类
System.out.println(dd instanceof DD);//true
System.out.println(dd instanceof CC);//true

CC cc = new DD();
System.out.println(cc instanceof DD);//true
System.out.println(cc instanceof CC);//true

Object obj=new Object();
System.out.println(obj instanceof DD);//false
System.out.println(obj instanceof CC);//false
}
}
class CC{}
class DD extends CC{}

2.4.7.3 动态绑定机制

  1. 当调用对象的方法时,该方法会和对象的运行类型绑定
  2. 当调用对象的属性时,没有动态绑定机制,那里调用那里使用
  3. 如果没有,则发挥继承机制查找
    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
    //Dynamic_binding.java  
    public class Dynamic_binding {
    public static void main(String[] args) {
    //编译类型AAA,运行类型BBB
    AAA a = new BBB();
    //调用链:子类找sum有,直接使用子类sum
    System.out.println(a.sum()); //40
    //调用链:子类找sum1有,直接使用子类sum1
    System.out.println(a.sum1());; //30
    //注销掉子类的sum方法的调用链:
    // 子类找sum没,去父类找到使用父类sum,但是父类中有个getI方法,但是子类父类都有,用哪个呢?这时就看运行类型是谁就用谁的,如果子类没有sum方法,就找父类,父类也没有,就报错
    System.out.println(a.sum());//30
    //注销掉子类的sum1方法的调用链:
    //子类找sum1没,去父类找到使用父类sum1,但是父类中有个变量i,这个用谁的呢?答案:用父类的
    System.out.println(a.sum1());//20
    //结论:
    // 1.当调用对象的方法时,该方法会和对象的运行类型绑定
    // 2.当调用对象的属性时,没有动态绑定机制,那里就调用那里使用
    // 3.如果没有,则发挥继承机制查找
    }
    }

    class AAA{
    public int i=10;
    public int sum(){
    return getI()+10;
    }
    public int getI(){
    return i;
    }
    public int sum1(){
    return i+10;
    }
    }
    class BBB extends AAA{
    public int i=20;
    public int sum(){
    return i+20;
    }
    public int getI(){
    return i;
    }
    public int sum1(){
    return i+10;
    }
    }

2.4.8 Object类

所有类的根类,所有类默认继承自Object类

2.4.8.1 ==和equal

==是比较运算符
1.可以比较基本类型,也可以比较引用类型
2.如果比较基本类型,则比较值是否相等
3.如果比较引用数据类型,则比较的是指针的指向是否相等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Object_test01  
public class Object_test01 {
public static void main(String[] args) {
//此处的等于是基本数据类型的比较
int num1=100;
int num2=100;
int num3=200;
System.out.println(num1==num2);//true
System.out.println(num1==num3);//false
//此处的等于是引用类型的比较,即指针的比较
XX x0 = new XX();
XX x1 = x0;
XX x2 = new XX();
System.out.println(x1==x0);//true
System.out.println(x1==x2);//false

YY yy = new YY();
XX x3 = yy;
System.out.println(yy==x3);//true
}
}
class XX{}
class YY extends XX{}

equal:Object默认是比较两个对象是否一样,只能判断引用类型
其他很多类都重写了该方法,比较的内容与具体实现有关

1
2
3
4
5
6
7
8
9
10
//Object_test01  
public class Object_test01 {
public static void main(String[] args) {
String str1 = new String("String");
String str2 = new String("String");
//可以切到equal原码进行查看
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2));//true
}
}

2.4.8.2 hashcode

  1. 如果两个引用指向同一对象,则哈希值一样
  2. 如果两个引用指向不是统一对象,则哈希值不一样
  3. 类似指针理解,内存地址
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //Object_test02.java  
    public class Object_test02 {
    public static void main(String[] args) {
    X x = new X();
    X x1 = new X();
    X x2=x;
    System.out.println("x的hash值="+x.hashCode());
    System.out.println("x1的hash值="+x1.hashCode());
    System.out.println("x2的hash值="+x2.hashCode());
    Y y = new Y();
    System.out.println("y的hash值="+y.hashCode());

    }
    }
    class X{}
    class Y{}

2.4.8.3 toStirng

  • Object类的实现
    1
    2
    3
    4
    //返回完整类名和16进制哈希值
    public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
  • 重写实现
    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
    //Object_test03.java  
    public class Object_test03 {
    public static void main(String[] args) {
    Person_s person_s = new Person_s("张三", 18);
    //以下方式等价
    System.out.println(person_s);
    System.out.println(person_s.toString());
    }
    }
    class Person_s {
    private String name;
    private int age;

    public Person_s(String name, int age) {
    this.name = name;
    this.age = age;
    }

    public String getName() {
    return name;
    }

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

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }

    @Override
    public String toString() {
    return "Person_s{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
    }
    }

2.4.8.4 finalize(java9开始不鼓励使用)

垃圾回收器,类似析构函数
Object的finalize方法有接口没实现,需要可重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Object_test04.java  
public class Object_test04 {
public static void main(String[] args) {
Car car = new Car("宝马");
car = null;
//主动触发垃圾回收器,且不阻塞在此处(从输出结果可看出)
System.gc();
System.out.println("end");
}
}
class Car{
private String name;

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

@Override
protected void finalize() {
System.out.println("被当成垃圾回收啦。。。。");
}
}

2.5 递归

自身调用自己,从堆栈内存分析,好理解

2.5.1 汉诺塔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*  
汉诺塔问题
*/public class Hannuo {
public static void main(String[] args) {
int n=10;
save abc=new save();
abc.sava_hannuo(n,'a','b','c');
}
}

class save{
public void sava_hannuo(int n,char a,char b,char c){
if (n==1)
System.out.println(a+"->"+c);
else {
sava_hannuo(n-1,a,c,b);
System.out.println(a+"->"+c);
sava_hannuo(n-1,b,a,c);
}
}
}

2.5.2 斐波那契

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Fibonacci.java  
public class Fibonacci {
public static void main(String[] args) {
Save save = new Save();
System.out.println(save.Fibonacci(10));
}
}
class Save {
public int Fibonacci(int n)
{
if(n==1||n==2)
return 1;
else
return Fibonacci(n-1)+Fibonacci(n-2);
}
}

2.6 类变量

2.6.1 静态变量

静态变量使用static修饰,类加载的时候生成
特点:被同一个类的所有对象共享
访问控制权限依旧生效
可以通过对象名调用,也可以通过类名调用

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
//OOP_styatic_var.java  
public class OOP_styatic_var {
public static void main(String[] args) {
Game person1 = new Game("小王");
Game person2 = new Game("小李");
Game person3 = new Game("小赵");
person1.Games();
person1.count++;
person2.Games();
person2.count++;
person3.Games();
person3.count++;
System.out.println("一共有"+Game.count+"人在玩游戏");
}
}
class Game{
private String name;
public static int count=0;
public Game(String name){
this.name = name;
}
public void Games(){
System.out.println(this.name+"加入游戏");
}
}

2.6.2 静态方法

  1. 可以不创建对象就使用类的方法(类似的有Math类的一些方法)
  2. 提高开发效率
  3. 可以通过对象名调用,也可以通过类名调用
  4. 静态方法内不能使用this和super
  5. 静态方法只能访问静态成员
    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
    //OOP_styatic_methon.java  
    public class OOP_styatic_methon {
    public static void main(String[] args) {
    System.out.println(Tools.add(100,200));
    System.out.println(Tools.sub(100,200));
    System.out.println(Tools.mul(100,200));
    System.out.println(Tools.div(100,200));
    }
    }
    class Tools{
    public static int add(int a,int b)
    {
    return a+b;
    }
    public static int sub(int a,int b)
    {
    return a-b;
    }
    public static int mul(int a,int b)
    {
    return a*b;
    }
    public static int div(int a,int b)
    {
    return a/b;
    }
    }

2.6.3 代码块(类创建调用)

  1. 解决代码复用情况(多个构造器均引用的代码)
  2. 代码块调用的顺序优先于构造器
  3. 创建对象时调用
    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
    //CodeBlock.java  
    public class CodeBlock {
    public static void main(String[] args) {

    Movie movie = new Movie("你好,张三");
    System.out.println("===============");
    Movie movie2 = new Movie("人民的名义", 100, "李四");
    }
    }

    class Movie {
    private String name;
    private double price;
    private String director;

    {
    System.out.println("电影屏幕打开...");
    System.out.println("广告开始...");
    System.out.println("电影正是开始...");
    };

    public Movie(String name) {
    System.out.println("Movie(String name) 被调用...");
    this.name = name;
    }

    public Movie(String name, double price) {

    this.name = name;
    this.price = price;
    }

    public Movie(String name, double price, String director) {

    System.out.println("Movie(String name, double price, String director) 被调用...");
    this.name = name;
    this.price = price;
    this.director = director;
    }
    }

2.6.3.1 静态代码块(类加载调用)细节1

  1. 对象创建时调用(先类加载,按照继承关系,再创建对象)
  2. 子类创建时父类加载调用
  3. 使用类的静态属性或方法调用
  4. 且只加载一次
    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
    //CodeBlockDetail.java  
    public class CodeBlockDetail {
    private static BBB bbb;

    public static void main(String[] args)
    {
    //1.对象创建时调用
    // AAA aaa = new AAA();
    System.out.println("========================");
    //2.子类创建时父类加载调用
    BBB bbb = new BBB();
    System.out.println("========================");
    //3.使用类的静态属性或方法调用
    //4.一次加载类,只会被调用一次
    AAA.staticMethod();
    System.out.println(AAA.n);
    }
    }
    class AAA{
    public static int n=100;
    static {
    System.out.println("AAA的静态代码块");
    }
    public AAA()
    {
    System.out.println("AAA的构造方法");
    }
    public static void staticMethod()
    {
    System.out.println("AAA的静态方法");
    }
    }
    class BBB extends AAA{
    static {
    System.out.println("BBB的静态代码块");
    }
    public BBB()
    {
    System.out.println("BBB的构造方法");
    }
    }

2.6.3.2 静态代码块细节2

  1. 调用静态代码块和静态属性初始化变量时,优先级相同,(如果有多个静态代码块)按照顺序执行
  2. 调用普通代码块和普通属性初始化变量时,优先级相同,(如果有多个普通代码块)按照顺序执行
  3. 静态代码块优先级高于普通代码块
  4. 构造器最后执行(构造器中第一行隐藏super()和本类普通代码块)
    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
    //CodeBlockDetail2.java  
    public class CodeBlockDetail2 {
    public static void main(String[] args) {
    A a = new A();
    }
    }
    class A{
    //静态代码块
    public static int n=getN();
    static{
    System.out.println("A类静态代码块被初始化");
    }

    public static int getN(){
    System.out.println("A类静态变量n被初始化");
    return 10;
    }
    //普通代码块
    {
    System.out.println("A类普通代码块被初始化");
    }
    public int n2=100;
    public A(){
    System.out.println("A类构造方法被初始化");
    }
    }

2.6.4 类加载和创建对象执行过程

  1. 父类加载,执行父类静态代码块和静态属性初始化(同优先级)
  2. 子类加载,执行子类静态代码块和静态属性初始化(同优先级)
  3. 创建对象
  4. 执行子类构造器,进入super(),进入父类构造器,再进入父类的普通代码块和普通属性的初始化,执行结束super(),回到子类的构造器继续执行子类的普通代码块和普通属性的初始化
    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    //CodeBlockDetail3.java  
    public class CodeBlockDetail3 {
    public static void main(String[] args) {
    //1.类加载 先加载 父类 A02 再加载 B02 //2.创建对象 从子类的构造器开始
    new B02();//对象
    }
    }

    class A02 { //父类
    private static int n1 = getVal01();
    static {
    System.out.println("A02的一个静态代码块..");//(2)
    }
    {
    System.out.println("A02的第一个普通代码块..");//(5)
    }
    public int n3 = getVal02();//普通属性的初始化
    public static int getVal01() {
    System.out.println("getVal01");//(1)
    return 10;
    }

    public int getVal02() {
    System.out.println("getVal02");//(6)
    return 10;
    }

    public A02() {//构造器
    //隐藏
    //super()
    //普通代码和普通属性的初始化......
    System.out.println("A02的构造器");//(7)
    }
    }

    class B02 extends A02 { //

    private static int n3 = getVal03();

    static {
    System.out.println("B02的一个静态代码块..");//(4)
    }
    public int n5 = getVal04();
    {
    System.out.println("B02的第一个普通代码块..");//(9)
    }

    public static int getVal03() {
    System.out.println("getVal03");//(3)
    return 10;
    }

    public int getVal04() {
    System.out.println("getVal04");//(8)
    return 10;
    }
    public B02() {//构造器
    //隐藏了
    //super()
    //普通代码块和普通属性的初始化...
    System.out.println("B02的构造器");//(10)
    }
    }

三、java进阶

深入解读String类源码及其应用技巧 | 二哥的Java进阶之路 (javabetter.cn)