# java基础 **Repository Path**: java-route/java-foundation ## Basic Information - **Project Name**: java基础 - **Description**: No description available - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-26 - **Last Updated**: 2021-01-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README java基础学习路线 java基础语法 ### 逻辑运算符
&(逻辑与) &&(短路与) |(逻辑或) ||(短路或) !(逻辑非) ^(逻辑异或)
#### 区分:& 和 &&
相同点: & 和 && 的运算结果相同
相同点: 当符号左边是true时,二者都会执行符号右边的运算
不同点: 当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算
#### 区分:| 和 ||
相同点: | 和 || 的运算结果相同
相同点: 当符号左边是false时,二者都会执行符号右边的运算
不同点: 当符号左边是true时,| 继续执行符号右边的运算。而 || 不再执行符号右边的运算
#### 三元运算符
结构:(条件表达式)?表达式1:表达式2
说明:
条件表达式的结果为boolean类型
根据条件表达式真或假,决定执行表达式1,还是表达式2
如果表达式为true、则执行表达式1
如果表达式为false、则执行表达式2
java基础语法
### java基础语法结构的使用
#### switch结构的使用
不是条件表达式不能写Boolean
1、根据switch表达式种的值、依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。当调用完执行语句以后。则仍然继续向下执行其他case结构中的执行语句以后,则仍然继续向下执行其他case结构中的执行语句。直到遇到break关键字或此switch-case结构末尾结束为止。
2、break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出
``` public static void main(String[] args) { int num = 2; switch (num) { case 0: System.out.println("1"); case 1: System.out.println("2"); case 2: System.out.println("3"); break; default: System.out.println("4"); } }
``` 3、switch结构中的表达式,只能是如下的6中数据类型之一
byte、short、char、int、枚举类型(JDK5.0)、String类型(JDK7.0新增)
#### switch使用问题
1、JDK6之前、在switch() 括号里面写上字符就会报错、语法上过不去
2、在JDK8中、除了(枚举类型(JDK5.0))都可以写到switch中
3、case之后只能声明常量。不能声明范围
比如:
``` int num = 2; switch (num) { case num > 0: System.out.println("1"); default: System.out.println("2"); } ```
4、default:相当于if-else结构中的else
default结构是可选的。而且位置是灵活的
``` int num = 2; switch (num) { default: System.out.println(); case 0: System.out.println(); case 1: System.out.println(); } ```
### 流程控制
#### 循环语句的四个组成部分
①、初始化部分(init_statement)
②、循环条件部分(test_exp)-->是boolean类型的
③、循环体部分(body_statement)
④、迭代部分(alter_statement)
#### for循环
1、for循环结构
``` for(①;②;④){ ③ } ```
2、执行过程
1-->2-->3-->-->4-->2-->3-->4 ......直到2不成立
3、模糊练习
``` int num = 1; for(System.out.print('a');num<=3;System.out.print('c'),num++){ System.out.print('b'); } 答案:abcbcbc ```
#### while循环结构
1、while循环结构
``` ① while(②){ ③; ④; } ``` ``` 案列 public static void main(String[] args) { int count =0; int num = 0; while (num <= 100) { if(num%2!=0){ count+=num; System.out.println(num); } num++; } System.out.println(count); } ``` ##### while说明问题
1、写while循环千万小心不要丢了迭代条件、一旦丢失了,就可能导致死循环
2、写程序要避免死循环
3、区别:for循环和while循环的初始化条件部分的作用范围不同
#### do-while循环
1、do-while循环
``` ① do{ ③; ④; }while(②); ``` 2、执行过程
①-->③-->④-->②-->③-->④--...②终止条件
##### do-while问题说明
1、do-while循环至少会执行依次循环体
### 数组概述
#### 数组的理解:
数组(Array)是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名、并通过编号的方式对这些数据进行统一管理。
#### 数组的相关概念:
数组名
元素
角标、下标、索引
数组的长度,元素的个数
#### 数组的特点
1)、数组是有序排列的
2)、数组属于引用类型的变量。数组的元素,既可以是基本数据类型、也可以是引用数据类型
3)、创建数组对象会在内存中开辟一整块连续的空间
4)、数组的长度一旦确定。就不能修改
#### 数组的分类
1)、按照维数:一维数组、二维数组
2)、按照数组元素的类型、基本数据类型元素的数组、引用数据类型元素的数组
#### 一维数组的使用
① 一维数组的声明和初始化
``` //静态初始化:数组的初始化和元素的赋值操作同时进行 int[] i = new int[]{100, 200, 300};
//动态初始化:数组的初始化和数组元素的赋值操作分开进行 String[] str = new String[5]; ```
总结:一旦初始化完成、其长度就确定了
② 如何调用数组的指定位置的元素
``` String[] str = new String[5]; str[0] ="啊啊"; str[1] ="呃呃"; str[2] ="得到"; str[3] ="烦烦烦"; str[4] ="方法"; ```
③ 如何获取数组的长度
``` System.out.println(str.length); ```
④ 如何遍历数组
``` for (int i1 = 0; i1 < str.length; i1++) { System.out.println(str[i1]); } ```
⑤ 数组元素的默认初始化值
数组元素是整型:0
数组元素是浮点型:0.0
数组元素是char 型:0或'u0000',而非 '0'
数组元素是boolean型:false

数组元素是引用数据型:null
⑥ 数组的内存解析
#### 二维数组
##### 理解
对于二维数组的理解,我们可以看成是一维数组array1有作为另一个一维数组array2的元素存在。
其实,从数组底层的运行机制来看。其实没有多维数组。
##### 二维数组的使用
① 一维数组的声明和初始化
``` //静态初始化 int[][] num = new int[][]{{123, 123}, {123, 123}, {123, 123}}; //动态初始化 int[][] num1 = new int[3][2]; int[][] num3 = new int[3][]; //三个元素、每个元素都是都还没赋值那 /** * 3:代表二维数组里面长度是3、 * 2:每单个的数组里面是两个元素 */ ```
② 如何调用数组的指定位置的元素
``` //如何调用二维数组 System.out.println(num[0][1]); ``` ③ 如何获取数组的长度
``` //如何获取二维数组长度 System.out.println(num.length); System.out.println(num[0].length); ``` ④ 如何遍历数组
``` for (int i = 0; i < num.length; i++) { for (int i1 = 0; i1 < num[i].length; i1++) { System.out.print(num[i][i1] +" "); } System.out.println(); } ``` ⑤ 数组元素的默认初始化值
针对于初始化方式一:比如:int[][] arr = new int[4][3];
外层元素的初始化值为:地址值
内层元素的初始化值为:与一维数组初始化情况相同
针对于初始化方式二:比如:int[][] arr = new int[4][];
外层元素的初始化值为:null
内层元素的初始化值为:不能调用否则报错
⑥ 数组的内存解析
int[][] arr1 = new int[4][];
arr1[1] = new int[]{1,2,3};
arr1[2] = new int[4];
arr1[2][1] = 30 ;
图解:
### 面向对象 #### 面向对象三条主线 ``` 一、Java面向对象学习的三条主线:(第4-6章) 1.Java类及类的成员:属性、方法、构造器;代码块、内部类 2.面向对象的三大特征:封装性、继承性、多态性、(抽象性) 3.其它关键字:this、super、static、final、abstract、interface、package、import等 “大处着眼,小处着手” 二、“人把大象装进冰箱” 1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。 ① 把冰箱门打开 ② 抬起大象,塞进冰箱 ② 把冰箱门关闭 2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。 人{ 打开(冰箱){ 冰箱.开开(); } 抬起(大象){ 大象.进入(冰箱); } 关闭(冰箱){ 冰箱.闭合(); } } 冰箱{ 开开(){} 闭合(){} } 大象{ 进入(冰箱){ } } 三、面向对象的两个要素: 类:对一类事物的描述,是抽象的、概念上的定义 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance) >面向对象程序设计的重点是类的设计 >设计类,就是设计类的成员。 ``` #### 类中属性的使用 属性(成员变量) vs 局部变量 ##### 1.相同点: ``` 1.1 定义变量的格式:数据类型 变量名 = 变量值 1.2 先声明,后使用 1.3 变量都有其对应的作用域 ``` ##### 2、不同点 ``` 2.1 在类中声明的位置的不同 属性:直接定义在类的一对{}内 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量 2.2 关于权限修饰符的不同 属性:可以在声明属性时,指明其权限,使用权限修饰符。 常用的权限修饰符:private、public、缺省、protected --->封装性 目前,大家声明属性时,都使用缺省就可以了。 局部变量:不可以使用权限修饰符。 2.3 默认初始化值的情况: 属性:类的属性,根据其类型,都有默认初始化值。 整型(byte、short、int、long):0 浮点型(float、double):0.0 字符型(char):0 (或'\u0000') 布尔型(boolean):false 引用数据类型(类、数组、接口):null 局部变量:没有默认初始化值。 意味着,我们在调用局部变量之前,一定要显式赋值。 特别地:形参在调用时,我们赋值即可。 2.4 在内存中加载的位置: 属性:加载到堆空间中 (非static) 局部变量:加载到栈空间 ``` #### 类中方法的声明和使用 ##### 1、举例 ``` public void eat(){} public void sleep(int hour){} public String getName(){} public String getNation(String nation){} ``` ##### 2、方法的声明 ``` 权限修饰符 返回值类型 方法名(形参列表){ 方法体 } ``` ##### 3、说明 ``` 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说 3.2 返回值类型: 有返回值 vs 没有返回值 3.2.1 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用 return关键字来返回指定类型的变量或常量:“return 数据”。 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要 使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。 3.2.2 我们定义方法该不该有返回值? ① 题目要求 ② 凭经验:具体问题具体分析 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意” 3.4 形参列表: 方法可以声明0个,1个,或多个形参。 3.4.1 格式:数据类型1 形参1,数据类型2 形参2,... 3.4.2 我们定义方法时,该不该定义形参? ① 题目要求 ② 凭经验:具体问题具体分析 3.5 方法体:方法功能的体现。 ``` ##### 4、return关键字的使用 ``` 1.使用范围:使用在方法体中 2.作用:① 结束方法 ② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。 3.注意点:return关键字后面不可以声明执行语句。 ``` ##### 5、方法的使用中 ``` 1、方法的使用中,可以调用当前类的属性或方法 特殊的:方法A中又调用了方法A:递归方法。 方法中,不可以定义方法。 public static void main(String[] args) { Customer cust1 = new Customer(); // cust1.eat(); //测试形参是否需要设置的问题 // int[] arr = new int[]{3,4,5,2,5}; // cust1.sort(); cust1.sleep(8); //方法 public void eat(){ System.out.println("客户吃饭"); return; //return后不可以声明表达式 // System.out.println("hello"); } public void sleep(int hour){ System.out.println("休息了" + hour + "个小时"); eat(); //不递归 // sleep(10); //递归 } ``` #### 方法的重载(overload) ##### 概念 ``` 1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。 "两同一不同":同一个类、相同方法名 参数列表不同:参数个数不同,参数类型不同 2. 举例: Arrays类中重载的sort() / binarySearch() 3.判断是否是重载: 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系! 4. 在通过对象调用方法时,如何确定某一个指定的方法: 方法名 ---> 参数列表 ``` ##### 代码示例 ``` //如下的4个方法构成了重载 public void getSum(int i, int j) { System.out.println("1"); } public void getSum(double d1, double d2) { System.out.println("2"); } public void getSum(String s, int i) { System.out.println("3"); } public void getSum(int i, String s) { System.out.println("4"); } ``` #### 可变个数形参的方法 ##### 1.jdk 5.0新增的内容 ##### 2.具体使用: ``` 2.1 可变个数形参的格式:数据类型 ... 变量名 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。 2.5 可变个数形参在方法的形参中,必须声明在末尾 2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。 ``` ##### 2.代码示例: ``` public void show(int i) { } public void show(String s) { System.out.println("show(String)"); } public void show(String... strs) { System.out.println("show(String ... strs)"); for (int i = 0; i < strs.length; i++) { System.out.println(strs[i]); } } public static void main(String[] args) { //可变参数的使用、代替了数组 test.show(new String[]{"AA", "BB", "CC"}); } ``` #### 理解变量的赋值 ##### 概念 > 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。 > 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。 ##### 代码示例 ``` public class ValueTransferTest { public static void main(String[] args) { System.out.println("***********基本数据类型:****************"); int m = 10; int n = m; System.out.println("m = " + m + ", n = " + n); n = 20; System.out.println("m = " + m + ", n = " + n); System.out.println("***********引用数据类型:****************"); Order o1 = new Order(); o1.orderId = 1001; Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。 System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " + o2.orderId); o2.orderId = 1002; System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " + o2.orderId); } } class Order { int orderId; } ``` #### 面向对象的特征一 ##### 封装与隐藏 ``` 一、问题的引入: 当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到 属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值 加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs()) 同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private). -->此时,针对于属性就体现了封装性。 二、封装性的体现: 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值 拓展:封装性的体现:① 如上 ② 不对外暴露的私有的方法 ③ 单例模式 ... 三、封装性的体现,需要权限修饰符来配合。 1.Java规定的4种权限(从小到大排列):private、缺省、protected 、public 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类 3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类 修饰类的话,只能使用:缺省、public 总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。 高内聚、低耦合 高内聚:类的高部数据操作细节自己完成、不允许外部干涉 高耦合:紧对外暴漏少量的方法用于使用 优点: 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、 可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。 ``` ##### 四种权限修饰符 ##### 代码示例 ``` public class AnimalTest { public static void main(String[] args) { hxx hxx = new hxx(); hxx.setName("黄向向"); System.out.println(hxx.getName()); Animal a = new Animal(); a.name = "大黄"; // a.age = 1; // a.legs = 4;//The field Animal.legs is not visible a.show(); // a.legs = -4; // a.setLegs(6); a.setLegs(-6); // a.legs = -4;//The field Animal.legs is not visible a.show(); System.out.println(a.name); } } class Animal { String name; private int age; private int legs;//腿的个数 //对属性的获取 public int getLegs() { return legs; } //对属性的设置 public void setLegs(int l) { if (l >= 0 && l % 2 == 0) { legs = l; } else { legs = 0; // 抛出一个异常(暂时没有讲) } } public void eat() { System.out.println("动物进食"); } public void show() { System.out.println("name = " + name + ",age = " + age + ",legs = " + legs); } //提供关于属性age的get和set方法 public int getAge() { return age; } public void setAge(int a) { age = a; } } class hxx { private String name; private String green; public String getName() { return name; } public void setName(String n) { name = n; } } ``` #### 构造器 ##### 作用 ``` 一、构造器的作用: 1.创建对象 2.初始化对象的信息 二、说明: 1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器 2.定义构造器的格式:权限修饰符 类名(形参列表){} 3.一个类中定义的多个构造器,彼此构成重载 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器 5.一个类中,至少会有一个构造器。 ``` ##### 代码示例 ``` public class PersonTest { public static void main(String[] args) { //创建类的对象:new + 构造器 Person p = new Person(); p.eat(); Person p1 = new Person("Tom"); System.out.println(p1.name); } } class Person { //属性 String name; int age; //构造器 public Person() { System.out.println("Person()....."); } public Person(String n) { name = n; } // public Person(String n, int a) { name = n; age = a; } //方法 public void eat() { System.out.println("人吃饭"); } public void study() { System.out.println("人可以学习"); } } ``` #### this 关键 ##### 使用 ``` 1.this可以用来修饰、调用:属性、方法、构造器 2.this修饰属性和方法: this理解为:当前对象 或 当前正在创建的对象 2.1 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是, 通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式 的使用"this.变量"的方式,表明此变量是属性,而非形参。 2.2 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。 但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式 的使用"this.变量"的方式,表明此变量是属性,而非形参。 3. this调用构造器 ① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器 ② 构造器中不能通过"this(形参列表)"方式调用自己 ③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)" ④ 规定:"this(形参列表)"必须声明在当前构造器的首行 ⑤ 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器 ``` ##### 代码示例 ``` public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); p1.setAge(1); System.out.println(p1.getAge()); p1.eat(); System.out.println(); Person p2 = new Person("Jerry", 20); System.out.println(p2.getAge()); } } class Person { private String name; private int age; public Person() { // this.eat(); String info = "Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)"; System.out.println(info); } public Person(String name) { this(); this.name = name; } public Person(int age) { this(); this.age = age; } public Person(String name, int age) { this(age); this.name = name; //this.age = age; //Person初始化时,需要考虑如下的1,2,3,4...(共40行代码) } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } /** * 谁掉这个eat、我就掉它的study方法 */ public void eat() { System.out.println("人吃饭"); this.study(); } public void study() { System.out.println("人学习"); } } ``` #### 继承性 ##### 继承性的好处 > ① 减少了代码的冗余,提高了代码的复用性 > ② 便于功能的扩展 > ③ 为之后多态性的使用,提供了前提 ##### 继承性的格式 ``` class A extends B{} A:子类、派生类、subclass B:父类、超类、基类、superclass 2.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。 特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。 只有因为封装性的影响,使得子类不能直接调用父类的结构而已。 2.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。 子类和父类的关系,不同于子集和集合的关系。 extends:延展、扩展 ``` ##### Java中关于继承性的规定 > 1.一个类可以被多个子类继承。 > 2.Java中类的单继承性:一个类只能有一个父类 > 3.子父类是相对的概念。 > 4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类 > 5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法 > 6. 子类不能直接访问父类中私有的(private)的成员变量和方法。 ##### java.lang.Object > 1.如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类 > 2.所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类 > 3.意味着,所有的java类具有java.lang.Object类声明的功能。 #### 方法的重写(override / overwrite) > 重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 > 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时, 实际执行的是子类重写父类的方法。 ##### 重写的规定 ``` 方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{ //方法体 } 约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法 ① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同 ② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符 >特殊情况:子类不能重写父类中声明为private权限的方法 ③ 返回值类型: >父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void >父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类 >父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的 基本数据类型(必须也是double) ④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲) ********************************************************************** 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)。 ``` #### super关键字的使用 > 1.super理解为:父类的 2.super可以用来调用:属性、方法、构造器 ##### super调用属性和方法 3. super调用属性和方法 > 3.1 我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用 父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super." > 3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的 使用"super.属性"的方式,表明调用的是父类中声明的属性。 > 3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的 使用"super.方法"的方式,表明调用的是父类中被重写的方法。 ##### thi和super > this 属性和形参重名了、使用this 像构造函数 > super 子类重写了父类、但是还是想调用父类就用super.属性 > this调用当前对象属性、找不到去子类找、super直接去父类找、以及子类和父类属性同名时 ##### super调用构造器 ``` 4.super调用构造器 4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器 4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行! 4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现 4.4 在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列表)",则默认调用的是父类中空参的构造器:super() 4.5 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器 ``` #### 子类对象实例化过程 ##### 图解 > > 子类对象实例化全过程 ##### 从结果上来看(继承性) > 子类继承父类以后,就获取了父类中声明的属性或方法。 > 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。 ##### 从过程上来看 ``` 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器, 进而调用父类的父类的构造器 直到调用了java.lang.Object类中空参的构造器为止。 正因为加载过所有的父类的结构,所以才可以看到内存中有 父类中的结构,子类对象才可以考虑进行调用。 ``` > 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。 #### 面向对象特征之三 > 多态性 ##### 多态性 ``` 1.理解多态性:可以理解为一个事物的多种形态。 2.何为多态性: 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用) 3. 多态的使用:虚拟方法调用 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法, 但在运行期,我们实际执行的是子类重写父类的方法。 总结:编译,看左边;运行,看右边。 4.多态性的使用前提: ① 类的继承关系 ② 方法的重写 5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边) ``` ##### 例如 ``` 多态的使用:当调用子父类同名同参数的方法时、实际执行的是子类重写父类的方法 -----------虚拟方法调用 调用方法和属性时:编译,看左边;运行,看右边。 Person mp = new Man(); mp.eat(); mp.age = 25; ```