JavaSE——Java多态

本文详细解析Java中的继承与多态概念,包括子父类成员变量与方法的关系、构造函数的调用机制、final关键字的应用、抽象类与接口的特点,以及多态的运用与好处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


多态总结



本文根据毕老师Java基础视频和自己的理解总结了继承,接口实现, 多态和内部类的主要知识点

1. 什么是子父类的继承关系, 特点是什么?

a. 继承描述的是类与类的一种关系, 父类中描述的是所有继承子类所有的共性信息, 子类是父类的一个延续

b. 父类包含了一类事物的功能, 继承使子类无需自己创建就可直接获得这些功能 

c. 继承只能是单继承, 因为当多个父类中拥有多个同名方法时, 就不知道用那个方法了 

d. 而且, 如果有多级继承, 继承来的方法是直接父类的方法

e. 不可以在静态函数中使用 this/super关键字


2. 继承中, 子父类的成员变量是什么关系?

a. 子类自动得到父类的可访问变量, 即, 如未覆盖, 子类this引用自动指向父类的成员变量, 父类中的私有变量是得不到的

b. 内存中, 会先加载父类.class文件, 子父类同名的成员变量同时在内存中, 一个被this本类引用指向, 一个被super父类引用指向

c. 如果一定要调用父类的变量需要通过父类引用super.member来实现; 而a中情况,this,super指向内存中同一个继承来的变量

//成员变量的关系
class First{
     public String str="First str";      // --> 2.b
     public String strF="strF";          // --> 2.a
}
class Second extends First{
	 public String str="Second str"; // --> 2.b
	 public String strCompare="this.str="+super.str+"\nsuper.str="+this.str+"\ns.str="+str;
         // --> 2.b,c
}
public class ExtendsDemo{
    
    public static void main(String[] args){
    	Second s=new Second();
        System.out.println(s.strF);
        System.out.println(s.strCompare);  
       // System.out.println(this.str);  // --> 1.e
       // System.out.println(super.str); // --> 1.e     
    }
}
输出:

strF

this.str=First str

super.str=Second str

s.str=Second str

3. 继承中,子父类的方法是什么关系?

a. 子父类中一样的函数是复写关系

b. 复写的好处是, 避免了修改源码的过程, 通过继承老的类, 复写需要修改的方法

c.  复写时需要调用父类被复写方法的代码: method(){super.method();}

d. 子类复写父类, 需要保证子类的权限大于等于父类的权限

e. 静态只能复写静态

//成员方法的关系
class First{
     public void show(){  
    	 System.out.println("First's show");
     }
     public void firstOnly(){
    	 System.out.println("First");   // --> 3.b
     }
     public void show0(){};		// --> 3.d
     public static void fee(){};	// --> 3.e
}
class Second extends First{
	 public void show(){
 		 System.out.println("Second's show");
	 }
	 // void show0(){};  		// --> 3.d
	 // public void fee(){}; 	// --> 3.e
	 public void showFirst(){ 
		 super.show();   	// --> 3.c
	 }
}
public class ExtendsDemo{
    public static void main(String[] args){
    	Second s=new Second();
    	s.firstOnly();		        // --> First
    	s.show();			// --> Second's show
    	s.showFirst();                  // --> First's show
    }
}

4. 复写和重载的区别?

a. 复写的同名方法一定要子父类中一模一样

b. 重写的同名方法必须要求方法的参数列表不同

c. 只有返回类型值不同的方法是不容许定义的


5. 继承中,子父类的构造函数是什么关系?

a. 子类在加载时, 其构造函数上(无论是空否)都有一个隐式的super(); 相当于先加载父类的空构造函数,再加州本类的构造函数

b. 如果父类不存在空的构造函数,子类的构造函数中必须指定加载一个父类的构造函数

c. 总之, 子类必然要访问一个父类的构造函数,而且super()语句要写在子类构造函数的第一行

d. 复写时, 子类要调用本来构造方法, 用 this(), 而且也必须出现在第一行, 考虑c, 即复写时只能出现this()/super()其中一个

//构造函数的关系
class First{
	public First(){
		System.out.println("First run");
	}
	public First(String str){
		System.out.println("Frist("+str+") run");
	}
}
class Second extends First{
	 public Second(){    		// --> 5.a
		 System.out.println("Second run");
	 }
	 public Second(String str){    // --> 5.a
		 System.out.println("Second("+str+") run");
	 }
	 public Second(int num){
		 super("second(num)");   // --> 5.b,c
		 // 上一行替换为this();    // --> 5.d 
		 System.out.println("Second("+num+") run");
	 }
}
public class ExtendsDemo{
    public static void main(String[] args){
    	new Second();                   // --> First run Second run
    	new Second("a");                // --> First run Second("a") run 
    	new Second(1);                  // --> First(second(num)) run Second(1) run
    }
}

6. 为什么子类一定要加载父类的构造函数?

a. 构造函数可能接受一些成员初始化的值, 子类的成员可能需要依赖这些成员的初始化值


7. final关键字在类, 变量, 方法上分别是怎么用的, 定义成final的用处是什么?

a. 被final修饰的类不可以被继承, 可以避免用户通过一个子类继承的方式来改变这个类的所有属性

b. 被final修饰的方法不可以被子类复写, 给用户继承的权利,但是不可以改变某些方法的输出属性

c. 被final修饰的变量是一个常量,只能被赋值一次, 既可以修饰成员变量又可以修饰局部变量, 为了增强不可变数据的安全性

d. 内部类定义在类中的局部位置上时,只能访问局部被final修饰的局部变量


8. 抽象方法/类是什么, 有什么特点, 为什么要定义抽象?

a. 抽象方法是一种同类型(具体实现不同或不确定的)方法的抽取, 没有代码体, 不可以用new创建对象, 调用它也没有意义

b. 有抽象方法要被实用,必须由子类复写起所有的抽象方法后, 建立子类的对象调用

c. 抽象类是包含有抽象方法的类, 这其实是一种表示, 表明此类有需要复写内部的抽象方法

d. 如果一个抽象类的子类没有复写父类抽象类中所有的抽象方法, 那么这个子类还是一个抽象类

e. 抽象类可以没有一个抽象方法, 这样做的唯一一个目的就是不让这个类实例化


9. 接口是什么, 接口有什么特点?

a. 接口是将一些类所共有的方法抽取成一个功能描述的类, 所有子类可以实现这个接口中的方法以表征这个接口定义的功能, 

b. 接口定义了一类事物一种规则, 实现是一种规则的遵循; 

c. 接口在定义上可以理解为一个只包含常量(public static final)和/或抽象方法(public abstract)的抽象类

d. 接口中所有的成员都是public的

e. 接口中默认包含 public static final 和 public abstract关键字

f. 类与接口的关系叫implements, 一个类/接口可以implements多个接口

g. 接口于接口的关系还叫extends, 一个接口可以extends多个接口(注意,多个父接口中不可以有只有返回值不同的方法)

h. 接口不可以创建对象, 如果要实例化, 必须有一个可以实现此接口中所有方法的子实现类


// 接口示例
interface A{void methodA();}       // --> 9.e
interface B{void methodB();}       // --> 9.e
interface C extends A,B{void methodC();} // --> 9.g
interface D{
	public abstract void methodD();      // --> 9.c,d
	public static final double PI=3.14;  // --> 9.c,d
}
public class ImplementsDemo implements C1,D1 { // --> 9.f
	public void methodA(){};
	public void methodB(){};
	public void methodC(){};
	public void methodD(){};
	public static void main(String[] args) {
		System.out.println(new ImplementsDemo().PI); // --> 9.h
	}
}


10. 什么是多态, 多态的好处是? 

a. 多态可以是一类事物在不同分类,场合,的不同角色的体现, 这些角色的体现包含再该事物的继承和实现体系之中

b. 一个子类事物,可以作为一个父类或父接口的的角色被识别和接受, 即父类的引用接受了自己的子类对象

c. 多态的出现大大的提高了程序的可扩展性, 特别是体现在对方法参数的引用类型的向上装换上面

d. c的方法会牺牲子类的本类特殊功能的调用, 如果希望调用子类特殊功能, 需要进行向下类型转换(需要判断instanceof)

e. 虽然c在引用调用方法时收的引用类(父类)可见方法的限制, 调用的方法的仍然是对象中的方法(即子类中复写的方法体)

f. e的另一种说法是: 多态非静态方法编译时期看引用, 运行时期看对象; 

g. 静态方法/静态成员/非静态成员多态时无论编译和运行都只看引用;

//多态示例
abstract class Animal{
	abstract public void eat();
	public void sleep(){System.out.println("Zzz");}; 
}

class Cat extends Animal{
	public void eat(){System.out.println("Fish");}
	public void catchMouse(){System.out.println("Catch Mouse");}
}
class Dog extends Animal{
	public void eat(){System.out.println("Bone");}
	public void guardHouse(){System.out.println("Guard House");}
}
public class PolymorphismDemo {
	public static void main(String[] args) {
		doSomething(new Cat());
		doSomething(new Dog());
	}
	public static void doSomething(Animal a){
		a.eat();
		if(a instanceof Cat)         // --> 10.d,e
			((Cat) a).catchMouse();
		if(a instanceof Dog)         // --> 10.d,e
			((Dog) a).guardHouse();
		a.sleep();
	}
}

11. instanceof关键字如何理解?

a. instanceof 用来判断一个引用名称的对象是否是一个类的对象,父类的子类对象或者接口的子类实现

b. 无论引用是父类还是接口, 只看这个引用对用的对象

interface Man{}    class Father{}
class Son extends Father implements Man{}
public class InstanceofTest {
	public static void main(String[] args) {
		Son son=new Son();      // --> 11.a
		Father son1=new Son();  // --> 11.b
		Man son2=new Son();     // --> 11.b
		System.out.println((son instanceof Son)+","    // --> true,true,true
		  +(son instanceof Father)+","+(son instanceof Man)); 
		System.out.println((son1 instanceof Son)+","   // --> true,true,true
	          +(son1 instanceof Father)+","+(son1 instanceof Man));
		System.out.println((son2 instanceof Son)+","   // --> true,true,true
		  +(son2 instanceof Father)+","+(son2 instanceof Man));
	}
}

12. 内部类是什么, 有什么特点, 如何在内部类中调用外部类的成员, 如何在内部类调用外部类的成员?

a. 内部类是一个定义在一个类中的类, 内部类可以访问外部类中的成员包括私有

b. 外部类如果要访问内部类, 需要建立内部类对象

c. 内部类是一个类内部的成员,所以可以被多种修饰符修饰, 如 private, static


13. 如何在其他类中直接访问一个类的内部类中的成员, 如何区分内部类和外部类的同名成员?

a.  同样也需要建立一个内部类对象:  OuterName.InnerName  oi= new OuterName().new InnerName();

b. 一个有内部类的类有这样几个引用: 局部成员 x; 内部类成员: this.x 外部类成员: OuterName.this.x

c. 本类中访问会省略this或OuterName.this, 查找顺序是: 先检查局部, 在检查内部类引用, 再检查外部类引用, 先找到哪个就返回哪个值

//内部类示例
class Outer{
	int x=1;               // --> 13.b Outer.this.
	class Inner{
		int x=2;       // --> 13.b this.
		void show(){
			int x=3;
			System.out.println(x+" "+this.x+" "+Outer.this.x);
		}             // --> 13.c
	}
}

public class InnerTest {
	public static void main(String[] args) {
		Outer.Inner oi=new Outer().new Inner(); // --> 13.a
		oi.show();
	}
}

14. 内部类定义成static的时候有哪些要注意的?

a. static:内部类具有static特性;当内部类被static修饰后,只能访问外部类中static成员,出现访问局限。

b. 在外部其他类中,访问static内部类成员:new Outer.Inner().function(); //外部类名调用静态成员=>新建对象=>调用方法

c. 在外部其他类中,访问static内部static成员:new Outer.Inner.function();

d. 当内部类定义了static成员,内部类必须是static的(static部分先于外部类对象存在)

e. 当外部类中的static方法访问内部类时,内部类也必须是static; (static的外部类方法调用不需要对象,只有调用static的内部类才能被调用)


15. 局部内部类有哪些要注意的?

a. 不可以被成员修饰符修饰;

b. 可以直接访问外部类的成员,因为还持有外部类的引用;

c. 不可以访问它所在的局部中的变量,除非这个局部变量被final修饰

// 静态和局部内部类示例
class Outer{
	static int x=1;         // --> 14.a 
	static class Inner{     // --> 14.d,e
		void show(){    // --> 14.b
			System.out.println(x);
		}
		static void staticShow(){}; 
	}       // --> 14.c
	void fee(){
		//int x=0;   // --> 15.c 无法通过编译 需要final
		class InnerLocal{   // --> 15.a
			void foo(){
				System.out.println(x);
			}          // --> 15.b
		}
	}
}

public class InnerTest {
	public static void main(String[] args) {
		Outer.Inner oi=new Outer.Inner(); // --> 15.b
		oi.show();               
		Outer.Inner.staticShow();         // --> 15.c
	}
}

参考资料: 传智博客毕老师Java基础视频


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值