Java基础知识笔记(下)
面向对象
- 面向过程与面向对象都是我们编程中,编写程序的一种思维方式
* 面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程。 * 面向对象的程序设计方式,是遇到一件事时,思考“我该让谁来做”,然后那个“谁”就是对象,他要怎么做 * 面向对象好处 * a: 面向对象思维方式是一种更符合人们思考习惯的思想 * b: 面向过程思维方式中更多的体现的是执行者(自己做事情),面向对象中更多的体现是指挥者(指挥对象做事情)。 * c: 面向对象思维方式将复杂的问题简单化。
内存中方法调用完毕之后的小tips:
- 栈内存中方法执行完毕之后,出栈死亡,当main方法也执行完毕之后,main方法弹栈死亡,在堆内存中new的对象也变成了垃圾。
- 栈内存与堆内存不同,栈内存中的空间用完就释放;而栈内存中的对象或者数组,需要等着虚拟机来清理内存。
类与对象
类和对象的关系
- 类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体
- 举例
- 可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系
局部变量与成员变量的区别
- 区别一:定义的位置不同
- 定义在类中的变量是成员变量
- 定义在方法中或者{}语句里面的变量是局部变量
- 区别二:在内存中的位置不同
- 成员变量存储在堆内存的对象中
- 局部变量存储在栈内存的方法中
- 区别三:声明周期不同
- 成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失
- 局部变量随着方法的运行而出现在栈中,随着方法的弹栈而消失
- 区别四:初始化不同
- 成员变量因为在堆内存中,所有默认的初始化值
- 局部变量没有默认的初始化值,必须手动的给其赋值才可以使用。
封装
- A.面向对象三大特征
* 封装、继承、多态
- B.封装表现
- 1、方法就是一个最基本封装体
- 2、类其实也是一个封装体
- C.封装的好处
- 1、提高了代码的复用性
- 2、隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用。这是核心之一,也可以理解为就是封装的概念
- 3、提高了安全性
private关键字
- A.private概述
* private可以修饰成员内容包括成员方法和成员变量 * 被private修饰的内容不能在其他类访问(不允许外面的类,调用自己的成员变量)
this关键字
区分成员变量和局部变量的同名
- 当类中存在成员变量和局部变量同名的时候为了区分,就需要使用this关键字
- 方法中变量使用遵循就近原则
- this:本类的对象引用
继承
继承的概述
A:继承的概念
a:继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系
b:在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,
构建出来的新类被称作子类,现有类被称作父类
B:继承关系的子类特点
a:子类会自动拥有父类所有非private修饰的属性和方法
继承的格式
class 子类 extends 父类 {}
雇员(Employee)与研发部员工(Developer)案例:
定义员工类Employee
*/
class Employee {
String name;
public void work() {
System.out.println("尽心尽力地工作");
}
}
*Developer.java:
class Developer extends Employee {
public void printName() {
System.out.println("name=" + name);
}
}
*测试员工类与研发部员工类:
public class Example01 {
public static void main(String[] args) {
Developer d = new Developer();
d.name = "小明";
d.printName();
d.work();
}
}
*通过子类对象既可以调用自身的非private修饰的成员,也可以调用父类的非private修饰的成员
继承的好处
继承的好处: 1、继承的出现提高了代码的复用性,提高软件开发效率。 2、继承的出现让类与类之间产生了关系,提供了多态的前提。
继承的注意事项
在Java中,类只支持单继承,不允许多继承,也就是说一个类只能有一个直接父类,
例如下面这种情况是不合法的。
class A{}
class B{}
class C extends A,B{} // C类不可以同时继承A类和B类
在Java中,子类和父类是一种相对概念, 也就是说一个类是某个类父类的同时,也可以是另一个类的子类。
继承的体系
继承的体系:
动物(吃)
|
-------------------------
| |
猫科动物(吃,胎生) 爬行动物(吃,卵生)
| |
------------------------------- -----------------
| | | |
猫(吃,抓老鼠,胎生) 虎(吃,领地,胎生) 蛇(吃,冬眠,卵生) 鳄鱼(吃,潜水,卵生)
? ? 动物体系是对每个具体事物共性的抽取,子类的共性抽取形成父类 ? 父类:具有所有子类的共性内容 ? 子类:不但有共性还有自身特有的内容 ? 整个继承体系,越向上越抽象,越向下越具体
继承后子类父类成员变量的特点
子类的对象调用成员变量的时候,子类自己有,使用子类,子类自己没有调用的父类 子父类中出现了同名的成员变量时 在子类中需要访问父类中非私有成员变量时,需要使用super关键字
继承后子类父类成员方法的特性
子类重写父类方法
子类的对象调用方法的时候,子类自己有,使用子类,子类自己没有调用的父类
class Fu{
public void show(){
System.out.println("Fu类中的show方法执行");
}
}
class Zi extends Fu{
public void show2(){
System.out.println("Zi类中的show2方法执行");
}
}
public class Test{
public static void main(String[] args) {
Zi z = new Zi();
z.show();
z.show2();
}
}
为什么要有重写?
class Fu{
public void method(){
}
}
class Zi extends Fu{
}
c:子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为override重写、复写或者覆盖
class Fu{
public void show(){
System.out.println("Fu show");
}
}
class Zi extends Fu{
public void show(){
System.out.println("Zi show");
}
}
public class Test{
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
Fu类中的方法最先存在,那么如果项目需求变了, 该方法功能不能够满足我们的需求,此时我们也不会去改这个方法 因为项目中可能有大量的功能已经使用到该方法,如果随意修改可能使调用该方法的功能出现问题 所以使用重写方式基于原有功能提供更强的功能 权限:子类方法覆盖父类方法,必须要保证权限大于等于父类权限。 四大权限:public>默认=protected>private
重载与重写对比
重载:
权限修饰符(public private 默认):无关
方法名:重载的两个方法的方法名必须相同
形参列表:
形参类型的顺序不同
形参的个数不同
形参的类型不同
三者至少满足一个
返回值类型:
重载与返回值类型无关
重写:
权限修饰符(public private 默认):
子类方法的权限>=父类的方法的权限
方法名:
子类方法和父类方法必须相同
形参列表:
子类方法和父类方法的形参列表必须相同
返回值类型:
基本类数据类型:
必须相同
引用数据类型:
子类方法的返回值类型和父类方法的返回值类型相同
或者
子类方法的返回值类型是父类方法的返回值类型的 子类
抽象类
抽象类特点
A:抽象类的特点 a:抽象类和抽象方法都需要被abstract修饰。抽象方法一定要定义在抽象类中。 b:抽象类不可以直接创建对象,原因:调用抽象方法没有意义。 c:只有覆盖了抽象类中所有的抽象方法后,其子类才可以创建对象。否则该子类还是一个抽象类。 之所以继承抽象类,更多的是在思想,是面对共性类型操作会更简单。
abstract class A{
public abstract void func();
public abstract void func2();
}
class A2 extends A{
public void func(){}
public void func2(){}
}
抽象类一定是个父类? 是的,因为不断抽取而来的。 抽象类中是否可以不定义抽象方法? 是可以的,那这个抽象类的存在到底有什么意义呢?不让该类创建对象,方法可以直接让子类去使用 (适配器设计模式)
public abstract class Animal {
public void sleep(){
System.out.println("动物睡觉");
}
}
public class Cat extends Animal{
}
public class Test {
public static void main(String[] args) {
new Cat().sleep();
}
}
抽象关键字abstract不可以和哪些关键字共存? 1:private:私有的方法子类是无法继承到的,也不存在覆盖, 而abstract和private一起使用修饰方法,abstract既要子类去实现这个方法, 而private修饰子类根本无法得到父类这个方法。互相矛盾。
接口
接口概念
接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”。 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成。这样将功能的定义与实现分离,优化了程序设计。 请记住:一切事物均有功能,即一切事物均有接口。
接口定义
与定义类的class不同,接口定义时需要使用interface关键字。 定义接口所在的仍为.java文件,虽然声明时使用的为interface关键字的编译后仍然会产生.class文件。这点可以让我们将接口看做是一种只包含了功能声明的特殊类。
public interface 接口名 {
抽象方法1;
抽象方法2;
抽象方法3;
}
定义步骤 使用interface代替了原来的class,其他步骤与定义类相同: 接口中的方法均为公共访问的抽象方法 接口中无法定义普通的成员变量
接口的实现类
类与接口的关系
类与接口的关系为实现关系,即类实现接口。实现的动作类似继承,只是关键字不同,实现使用implements。 其他类(实现类)实现接口后,就相当于声明:”我应该具备这个接口中的功能”。实现类仍然需要重写方法以实现具体的功能。
实现格式
class 类 implements 接口 {
重写接口中方法
}
实现类注意事项
- 在类实现接口后,该类就会将接口中的抽象方法继承过来,此时该类需要重写该抽象方法,完成具体的逻辑。
- 接口中定义功能,当需要具有该功能时,可以让类实现该接口,只声明了应该具备该方法,是功能的声明。
- 在具体实现类中重写方法,实现功能,是方法的具体实现。
接口中成员变量的特点
接口中可以定义变量,但是变量必须有固定的修饰符修饰,public static final 所以接口中的变量也称之为常量,其值不能改变。
interface Demo {
public static final int NUM = 3;
}
接口中成员方法的特点
接口中可以定义方法,方法也有固定的修饰符,public abstract 类必须覆盖掉接口中所有的抽象方法后,子类才可以实例化。否则子类是一个抽象类。
interface Demo {
public abstract void show1();
public abstract void show2();
}
class DemoImpl implements Demo {
public void show1(){}
public void show2(){}
}
类和接口的多实现
了解了接口的特点后,那么想想为什么要定义接口,使用抽象类描述也没有问题,接口到底有啥用呢? 接口最重要的体现:解决多继承的弊端。将多继承这种机制在java中通过多实现完成了。
- 多实现的优点
- 怎么解决多继承的弊端呢?
- 弊端:多继承时,当多个父类中有相同功能时,子类调用会产生不确定性。
- 其实核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。
- 为什么多实现能解决了呢?
- 因为接口中的功能都没有方法体,由子类来明确。
interface Fu1{
void show1();
}
interface Fu2{
void show2();
}
class Zi implements Fu1,Fu2 {
public void show1(){}
public void show2(){}
}
类在继承类的同时实现多接口
- 继承的同时实现接口
- 接口和类之间可以通过实现产生关系,同时也学习了类与类之间可以通过继承产生关系。当一个类已经继承了一个父类,它又需要扩展额外的功能,这时接口就派上用场了。
- 子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。如果子类想要继续扩展其他类中的功能呢?这时通过实现接口来完成。
- 接口的出现避免了单继承的局限性。父类中定义的事物的基本功能。接口中定义的事物的扩展功能。
class Fu {
public void show(){}
}
interface Inter {
pulbic abstract void show1();
}
class Zi extends Fu implements Inter {
public void show1() {
}
}
接口的多继承
interface Fu1{
void show();
}
interface Fu2{
void show1();
}
interface Fu3{
void show2();
}
interface Zi extends Fu1,Fu2,Fu3{
void show3();
}
在开发中如果多个接口中存在相同方法,这时若有个类实现了这些接口,那么就要实现接口中的方法,由于接口中的方法是抽象方法,子类实现后也不会发生调用的不确定性。
接口的好处
- 总结:接口在开发中的它好处
- 1、接口的出现扩展了功能。
- 2、接口其实就是暴漏出来的规则。
- 3、接口的出现降低了耦合性,即设备与设备之间实现了解耦。
接口和抽象类的区别
- A: 明白了接口思想和接口的用法后,接口和抽象类的区别是什么呢?接口在生活体现也基本掌握,那在程序中接口是如何体现的呢?
通过实例进行分析和代码演示抽象类和接口的用法。
-
B: 举例:
- 犬:
行为: 吼叫; 吃饭; - 缉毒犬:
行为: 吼叫; 吃饭; 缉毒; -
由于犬分为很多种类,他们吼叫和吃饭的方式不一样,在描述的时候不能具体化,也就是吼叫和吃饭的行为不能明确。 -
当描述行为时,行为的具体动作不能明确,这时,可以将这个行为写为抽象行为,那么这个类也就是抽象类。 -
可是当缉毒犬有其他额外功能时,而这个功能并不在这个事物的体系中。这时可以让缉毒犬具备犬科自身特点的同时也有其他额外功能,可以将这个额外功能定义接口中。
interface 缉毒{
public abstract void 缉毒();
}
abstract class 犬科{
public abstract void 吃饭();
public abstract void 吼叫();
}
class 缉毒犬 extends 犬科 implements 缉毒{
public void 缉毒() {
}
void 吃饭() {
}
void 吼叫() {
}
}
class 缉毒猪 implements 缉毒{
public void 缉毒() {
}
}
接口和抽象类区别总结
-
相同点: 都位于继承的顶端,用于被其他类实现或继承;
都不能直接实例化对象;
都包含抽象方法,其子类都必须覆写这些抽象方法;
-
区别: 抽象类为部分方法提供实现,避免子类重复实现这些方法,提高代码重用性;接口只能包含抽象方法;
一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口;(接口弥补了Java的单继承)
抽象类是这个事物中应该具备的内容, 继承体系是一种 is..a关系
接口是这个事物中的额外内容,继承体系是一种 like..a关系
-
二者的选用: 优先选用接口,尽量少用抽象类;
需要定义子类的行为,又要为子类提供共性功能时才选用抽象类;
多态
多态概念
-
多态是继封装、继承之后,面向对象的第三大特性。 现实事物经常会体现出多种形态,如学生,学生是人的一种,
则一个具体的同学张三既是学生也是人,即出现两种形态。
-
Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。 -
Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。 如Student类可以为Person类的子类。
那么一个Student对象既可以赋值给一个Student类型的引用,也可以赋值给一个Person类型的引用。
-
最终多态体现为父类引用变量可以指向子类对象。 多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。 -
在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
多态调用的三种格式
* A: 多态的定义格式:
* 就是父类的引用变量指向子类对象
父类类型 变量名 = new 子类类型();
变量名.方法名();
* B: 普通类多态定义的格式
父类 变量名 = new 子类();
举例:
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
* C: 抽象类多态定义格式
抽象类 变量名 = new 抽象类子类();
举例:
abstract class Fu {
public abstract void method();
}
class Zi extends Fu {
public void method(){
System.out.println(“重写父类抽象方法”);
}
}
Fu fu= new Zi();
* D: 接口多态定义的格式
接口 变量名 = new 接口实现类();
如: interface Fu {
public abstract void method();
}
class Zi implements Fu {
public void method(){
System.out.println(“重写接口抽象方法”);
}
}
Fu fu = new Zi();
* E: 注意事项
同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个子类重写后的方法。
如 Person p1 = new Student();
Person p2 = new Teacher();
p1.work();
p2.work();
当变量名指向不同的子类对象时,由于每个子类重写父类方法的内容不同,所以会调用不同的方法。
多态成员的特点
* A: 掌握了多态的基本使用后,那么多态出现后类的成员有啥变化呢?
* 前面学习继承时,我们知道子父类之间成员变量有了自己的特定变化,
* 那么当多态出现后,成员变量在使用上有没有变化呢?
* 多态出现后会导致子父类中的成员变量有微弱的变化
*
* * B: 代码演示
class Fu {
int num = 4;
}
class Zi extends Fu {
int num = 5;
}
class Demo {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num);
Zi z = new Zi();
System.out.println(z.num);
}
}
* C: 多态成员变量
当子父类中出现同名的成员变量时,多态调用该变量时:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。编译运行看左边。
* D: 多态出现后会导致子父类中的成员方法有微弱的变化。看如下代码
class Fu {
int num = 4;
void show() {
System.out.println("Fu show num");
}
}
class Zi extends Fu {
int num = 5;
void show() {
System.out.println("Zi show num");
}
}
class Demo {
public static void main(String[] args) {
Fu f = new Zi();
f.show();
}
}
* E: 多态成员方法
编译时期:参考引用变量所属的类,如果没有类中没有调用的方法,编译失败。
运行时期:参考引用变量所指的对象所属的类,并运行对象所属类中的成员方法。
简而言之:编译看左边,运行看右边。
- 多态中,成员特点
- 成员变量:
- 编译的时候, 参考父类中有没有这个变量,如果有,编译成功,没有编译失败
- 运行的时候, 运行的是父类中的变量值
- 编译运行全看父类
- 成员方法:
- 编译的时候, 参考父类中有没有这个方法,如果有,编译成功,没有编译失败
- 运行的时候, 运行的是子类的重写方法
- 编译看父类,运行看子类
instanceof关键字
* A: 作用
可以通过instanceof关键字来判断某个对象是否属于某种数据类型。
如学生的对象属于学生类,学生的对象也属于人类
* 格式:
boolean b = 对象 instanceof 数据类型;
* 举例:
Person p1 = new Student();
boolean flag = p1 instanceof Student;
boolean flag2 = p2 instanceof Teacher;
多态-向上转型
向上转型:当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。
使用格式:
父类类型 变量名 = new 子类类型();
如:Person p = new Student();
多态-向下转型
向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。 如果是直接创建父类对象,是无法向下转型的! 使用格式: 子类类型 变量名 = (子类类型) 父类类型的变量; 如:Student stu = (Student) p; //变量p 实际上指向Student对象
多态的好处和弊端
* A: 多态的好处和弊端
* 当父类的引用指向子类对象时,就发生了向上转型,即把子类类型对象转成了父类类型。
向上转型的好处是隐藏了子类类型,提高了代码的扩展性。
* 但向上转型也有弊端,只能使用父类共性的内容,而无法使用子类特有功能,功能有限制。
* B: 看如下代码
abstract class Animal {
abstract void eat();
}
class Dog extends Animal {
void eat() {
System.out.println("啃骨头");
}
void lookHome() {
System.out.println("看家");
}
}
class Cat extends Animal {
void eat() {
System.out.println("吃鱼");
}
void catchMouse() {
System.out.println("抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
a.eat();
if( !a instanceof Dog){
System.out.println("类型不匹配,不能转换");
return;
}
Dog d = (Dog) a;
d.lookHome();
}
}
* C 多态总结:
什么时候使用向上转型:
当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,这时就可以使用向上转型。
如:Animal a = new Dog();
a.eat();
什么时候使用向下转型
当要使用子类特有功能时,就需要使用向下转型。
如:Dog d = (Dog) a;
d.lookHome();
向下转型的好处:可以使用子类特有功能。
弊端是:需要面对具体的子类对象;在向下转型时容易发生ClassCastException类型转换异常。在转换之前必须做类型判断。
如:if( !a instanceof Dog){…}
构造方法
构造方法的作用
在new的同时给成员变量赋值,给对象属性进行初始化。
Perons p = new Person("张三",23);
在new 的时候给p对象的name属性和age属性进行赋值,使这个对象的属性有值。
构造方法定义
A: 构造方法定义
构造方法的格式:
修饰符 构造方法名(参数列表)
{
}
* B: 构造方法的体现:
构造方法没有返回值类型。也不需要写返回值。因为它是为构建对象的,对象创建完,方法就执行结束。
构造方法名称必须和类型保持一致。
构造方法没有具体的返回值。
构造方法的代码体现:
* C: 构造方法举例
class Person {
private int age;
private String name;
Person(int a, String nm) {
age = a;
name = nm;
}
}
* D: 构造方法运行特点:
在new 对象的时候自动调用执行。
默认添加的构造方法
- A: 每一class类都必须有一个构造方法,构造方法不写也有。
编译的时候,javac,系统会自动检查类中是否有构造方法,如果没有编译器就会自动添加一个构造方法 比如Person类, 编译器添加一个无参构造 public Person(){}
构造方法的调用赋值
* A: 理解构造方法的格式和基本功能之后,现在就要研究构造方法是怎么执行的呢?
* 在创建对象的时候是如何初始化的呢?
构造方法是专门用来创建对象的,也就是在new对象时要调用构造方法。
现在来看看如何调用构造方法。
* B: 案例
class Person {
private int age;
private String name;
Person(int a, String nm) {
age = a;
name = nm;
}
public void speak() {
System.out.println("name=" + name + ",age=" + age);
}
}
class PersonDemo {
public static void main(String[] args) {
Person p2 = new Person(23, "张三");
p2.speak();
}
}
上述代码演示了创建对象时构造方法的调用。即在创建对象时,会调用与参数列表对应的构造方法
构造方法的内存
内存加载的过程 有一个Person类, 创建Person 对象new Person() 1、首先会将main方法压入栈中,执行main方法中的 new Person(23,“张三”); 2、在堆内存中分配一片区域,用来存放创建的Person对象,这片内存区域会有属于自己的内存地址(0x88)。然后给成员变量进行默认初始化(name=null,age=0)。 3、执行构造方法中的代码(age = a ; name = nm;),将变量a对应的23赋值给age,将变量nm对应的”张三赋值给name,这段代码执行结束后,成员变量age和name的值已经改变。执行结束之后构造方法弹栈,Person对象创建完成。将Person对象的内存地址0x88赋值给p2。
构造方法的重载
* A:当在描述事物时,要不要在类中写构造方法呢?
* 这时要根据描述事物的特点来确定,当描述的事物在创建其对象时就要明确属性的值,
* 这时就需要在定义类的时候书写带参数的构造方法。
* 若创建对象时不需要明确具体的数据,这时可以不用书写构造方法(不书写也有默认的构造方法)。
构造方法的细节:
1、一个类中可以有多个构造方法,多个构造方法是以重载的形式存在的
2、构造方法是可以被private修饰的,作用:其他程序无法创建该类的对象。
* B: 举例
class Person {
private int age;
private String name;
private Person() {
}
Person(int a) {
age = a;
}
Person(String nm, int a) {
name = nm;
age = a;
}
}
构造方法和一般方法区别
* A: 目前为止,学习两种方法,分别为构造方法和一般方法,那么他们之间有什么异同呢?
1.格式不同
构造方法 : 修饰符 类名(参数类型 参数 ...){
初始化成员变量
}
一般方法: 需要有返回值类型
2.作用不同
构造方法一般用来给成员变量初始化;
一般方法根据需求而定;
3.调用方式不同
构造方法创建对象时调用, 或者this() super() 语句调用
普通方法需要对象调用或者静态方法直接调用静态方法.
4.执行不同
构造方法在对象创建时就执行了,而且只执行一次。
一般方法是在对象创建后,需要使用时才被对象调用,并可以被多次调用。
this在构造方法之间的调用
* A: 在之前学习方法之间调用时,可以通过方法名进行调用。
* 可是针对构造方法,无法通过构造方法名来相互调用。
构造方法之间的调用,可以通过this关键字来完成。
构造方法调用格式:
this(参数列表);
* B:调用构造方法的案例
class Person {
private int age;
private String name;
Person() {
}
Person(String nm) {
name = nm;
}
Person(String nm, int a) {
this(nm);
age = a;
}
}
super关键字
- A: 子父类中构造方法的调用
在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();语句。 - B: 格式:
调用本类中的构造方法 this(实参列表); 调用父类中的空参数构造方法 super(); 调用父类中的有参数构造方法 super(实参列表);
* A:子类构造方法,有一个默认添加的构造方法
public class Student extends Person {
public Student(){
super();
}
}
* B :为什么子类对象创建都要访问父类中的构造方法?
* 因为子类继承了父类的内容,所以创建对象时,必须要先看父类是如何对其内容进行初始化的,看如下程序
public class Test {
public static void main(String[] args) {
new Zi();
}
}
class Fu{
int num ;
Fu(){
System.out.println("Fu构造方法"+num);
num = 4;
}
}
class Zi extends Fu{
Zi(){
System.out.println("Zi构造方法"+num);
}
}
执行结果:
Fu构造方法0
Zi构造方法4
通过结果发现,子类构造方法执行时中,调用了父类构造方法,这说明,子类构造方法中有一句super()。
那么,子类中的构造方法为什么会有一句隐式的super()呢?
原因:子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。
这样,才可以使用父类中的内容。
当父类中没有空参数构造方法时,子类的构造方法必须有显示的super语句,指定要访问的父类有参数构造方法。
|