java面向对象14多态性与instanceof关键字的理解

本文深入探讨Java面向对象编程中的多态性概念,包括对象的多态性、虚拟方法调用、方法重写与重载的区别,以及多态性的运行时绑定特性。通过实例讲解如何在编译和运行时正确理解和应用多态性,提高代码的通用性和可维护性。

/*

  • java面向对象三大特性之多态性
  • 1,多态性可以理解为一个事物的多种形态
  • 2,对象的多态性:父类的引用指向子类的对象或者说子类的对象赋给父类的引用。
  • 3,多态的使用:虚拟方法调用
  • 子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父
  • 类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法
  • 确定的。所以多态性是运行时行为,而非编译时行为。
  • 对象有了多态性以后,在编译期,只能调用父类中声明的方法,在运行时,实际执行的是
  • 子类重写父类的方法,编译看左侧,运行看右侧。
  • 4,多态性使用的前提,1,类有继承关2,子类中有重写的方法,否则没有必要使用多态性。
  • 5,多态性适用于方法,不适用于属性。属性的编译和运行都看左侧。
  • 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
  • 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量
  • 6,方法重载与重写:
  • 重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不
  • 同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了
  • 不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类
  • 和子类的,即子类可以重载父类的同名不同参数的方法。
  • 所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,
  • 这称为“早绑定”或“静态绑定”; 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体
  • 方法,这称为“晚绑定”或“动态绑定”。
  • 7,多态总结:
  • 多态的作用:提高代码通用性,常称作接口重用
  • 多态的前提:需要存在继承或者实现关系,子类中有方法的重写
  • 多态的效果:编译时:要查看引用变量所声明的类(父类)中是否有所调用的方法。运行时:调用实际new的对象所属的类(子类)中的重写方法。
  • 类中的属性:成员变量不具备多态性,只看引用变量所声明的类的属性。
  • 8有了对象的多态性以后,内存中依然加载了子类的属性和方法,由于对象声明为父类类型,导致编译时只能调用父类的属性和方法
  • ,子类特有的属性和方法无法调用。
  • 如果想要调用子类的属性和方法,需要使用向下转型的方式将对象转换为子类对象
  • 类似基本数据类型的强制转换会出现精度损失的问题,向下转型有可能失败(classcastexception)的问题,必须有继承关系才能向下转型。
  • 需要先用 instanceof关键字判断对象是否是类的实例,如是返回true可以转型,否则返回false。
  • 注意:多态(向上转型)与强制类型转换(向下转型)不限于直接父类和直接子类,父类对象可以被孙类赋值,使用孙类重写方法。
  • 也可以强制转换为孙类对象,调用孙类特有的属性和方法。
  • 9,类B为类A的父类, 如果对象a instanceof 类A为true,那么a instanceof B也为true。
  • 如果类C为类A的子类,那么对于A类的实例化对象a有a instanceof C为false。

**

个人理解

instanceof关键字判断的是,被判断的类A的结构是否存在于在对象a的内存结构中,如果有则返回true,否则返回false。

类C为类A的子类,包含超出类A的方法和属性,在对象a的内存结构中不存在,a instanceof C就会返回false,
类D与类A类B类C不存在继承关系,其中的结构在对象a的内存中也不存在,a instanceof D也会返回false。

也只有在返回true 的情况下,a才能调用类A的所有结构,强制转换才能成功。

类B为类A的父类, 当向上类型转换(多态性) B b = new A();时,b的内存空间中拥有父类B与子类A的所有结构,所以 b instanceof A 返回true,表示b可以向下转型为A的对象。

在 A a = (A)b;向下转型时,a可以调用类A的结构**

*/

package object_chapter2;

import java.util.Random;

public class Object_Polymorphism {
  public static void main(String[] args) {
	
	Person p = new Person();
	p.eat();
	System.out.println(p.number);
	p = new Man();//多态的形式,父类的引用指向子类的对象
	p.eat();//多态的使用,执行的是子类重写的方法,称作虚拟方法调用
	//p.work();//子类特有的方法无法调用
	System.out.println(p instanceof Man);//使用instanceof判断p的结构是否存在于Man类中
 	Man m = (Man)p;//使用向下转型的方式调用子类的方法
//	Women w = (Women)p;//可以编译过,但运行出错,p的结构中有Man类的结构,但Man类的部分结构与Women不同,无法强转到Women。
//	w.investigate();
	System.out.println(p instanceof Women);
	m.work();
	p = new Women();
	p.eat();
	System.out.println(p.number);//输出的依然是父类属性的值
	//p.investigate();
	Object_Polymorphism o = new Object_Polymorphism();
	o.function(new Person());//正常调用
	o.function(new Man());//参数使用子类对象赋值,执行子类重写方法
	o.function(new Women());
    int value = new Random().nextInt(2);//输出随机数,0或1
    System.out.println(value);
    Person p1 = o.getInstance(value);
    p1.eat();//输出结果根据随机数确定,说明多态性是运行时行为
    
    Base base = new Sub();//多态性,子类对象赋值
	base.add(1, 2, 3);//调用的是子类中的重写的方法,没有重写则调用父类中的方法

	Sub s = (Sub)base;//强制类型转换为sub类型的对象
	s.add(1,2,3);//先调用确定形参的方法,没有再调用可变形参的方法,都没有再调用父类方法
}
  public Person getInstance(int value) {
	  switch (value) {
	  case 0:
		return new Man();
	  default:
		return new Women();
	}
  }
  
  public void function(Person p) {//方法中参数声明的是父类person的对象
	  p.eat();//方法体中执行父类的方法
	   if(p instanceof Man) {
		  Man m = (Man)p;
		  m.game();
	  }else if(p instanceof Women) {
		  Women w = (Women)p;
		  w.shopping();
	  }
  }
//  public void function(Man m) {//使用多态性可以省略这些重载的方法
//	  m.eat();
//  }
//  public void function(Women w) {
//	  w.eat();
//  }
  public void method(Object obj) {//因为Object类是所有类的父类,此处可以用任意类的对象赋值
	
  }
  
}

class Person{
   String name;
   int age;
   int number = 2;
   void move() {
	   System.out.println("运动是放电");
   }
   void eat() {
	   System.out.println("进食是充电");
   }
   void talk(){
	   System.out.println("通话基本靠吼");
   }
   void walk() {
	   System.out.println("交通基本靠走");
   }
   
}

class Man extends Person{
	int number = 1;
	void eat() {
		System.out.println("吃得多,干的多");
	}
	void work() {
		System.out.println("努力工作赚钱");
	}
}

class Women extends Person{
	int number = 0;
	void eat() {
		System.out.println("吃的少,身材好");
	}
	void investigate() {
		System.out.println("收集信息,坐镇指挥");
	}
}

class Base {
	public void add(int a, int... arr) {
		System.out.println("base");
	}
}

class Sub extends Base {

	public void add(int a, int[] arr) {//可变形参与数组相同,构成方法的重写
		System.out.println("sub_1");
	}

    public void add(int a, int b, int c) {//不构成方法 的重写,构成重载
		System.out.println("sub_2");
	}

}

/向下转型之后,依然是编译看左边,运行看右边,调用 的还是子类重写方法,与()内的类型无关,只是
//在编译时可以调用()内类型的特有结构,不会出现编译错误,()内的类型只对属性有影响,在属性同名的情况下
//调用的是()内类型的属性值。
public class Test {
public static void main(String[] args) {
AA a = new AA();
a.say();
AA b = new BB();
b.say();//调用子类方法
AA c = new CC();
c.say();//调用子类方法
System.out.println("----------");
System.out.println(a.i);
System.out.println(b.i);//调用父类属性
System.out.println(c.i);//调用父类属性
System.out.println("----------");
BB b1 = (BB)c;//向下转型为BB类型
b1.say();//依然调用CC类的方法
System.out.println(b1.i);//调用BB类属性

}

}

class AA{
int i =10;
void say() {
System.out.println(i);
}
}

class BB extends AA{
int i = 20;
void say() {
System.out.println(i);
}
}
class CC extends BB{
int i = 30;
void say() {
System.out.println(i);
}
}

<think>首先,用户的问题是:“我想了解Java面向对象多态性的相关知识 请问Java面向对象多态性的详细介绍”。根据系统指令,我必须遵循以下几点: 1. **行内数学表达式**:如果出现数学相关内容,要用 `$...$` 格式。但在这个问题中,是关于Java多态性,不太可能涉及数学表达式,所以我可能不需要使用这个。 2. **独立公式**:同样,不太可能涉及数学公式。 3. **LaTeX语法正确**:确保在任何LaTeX使用中语法正确。 4. **使用中文回答**:整个回答必须用中文。 5. **生成相关问题**:在回答末尾,我需要生成相关问题列表。 6. **引用的段落末尾自然地添加引用标识**:例如,[^1]。用户提供了几个引用:[^1], [^2], [^3], [^4],我应该引用这些来支持我的回答。 用户提供了四个引用: - 引用[1]:关于Java多态性的概念,通过方法重写和方法重载实现。 - 引用[2]:区分运行时多态,通过继承和接口实现。 - 引用[3]:多态性面向对象三大基本特性之一,强调运行时绑定。 - 引用[4]:提到了static方法限制和面向对象设计思想。 用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 但在这个对话中,这是第一次交互,没有上一次的问题和回答。系统指令中说“参考用户上一次的问题和你的回答”,但这里没有,所以我应该基于当前问题和提供的引用。 我的回答需要结构清晰,帮助用户逐步解决问题。既然问题是关于Java多态性的详细介绍,我应该组织成一个连贯的讲解。 结构建议: 1. **介绍多态性**:定义多态性,解释它在面向对象编程中的地位。 2. **核心概念**: - 运行时多态(动态多态) - 编译时多态(静态多态):方法重载 - 方法重写 3. **实现方式**: - 通过接口 - 通过继承 4. **优点**:提高代码可维护性、可扩展性、可读性。 5. **注意事项**:如不能用于static方法等。 6. **示例**:提供Java代码示例来演示多态性。 7. **结尾相关问题**:生成相关问题。 确保引用标识:在引用相关内容时,末尾添加[^1], [^2]等。 例如,如果我说“多态性通过方法重写和方法重载实现”,然后添加[^1],因为引用[1]提到了这个。 现在,组织内容: - **什么是多态性?**:多态性允许同一操作作用于不同对象时产生不同行为。是面向对象编程的核心特性之一。[^3] - **两种主要类型**: - 编译时多态:通过方法重载实现。 - 运行时多态:通过方法重写实现,结合继承和接口。[^2] - **实现细节**: - 方法重载:在同一类中,方法名相同但参数不同。 - 方法重写:在子类中覆盖父类的方法。 - **优点**:提高代码的灵活性和复用性。[^1] - **限制**:不能在static方法中使用this/super;多态只适用于实例方法。[^4] - **示例**:提供一个简单的Java代码示例。 代码示例: ```java class Animal { void speak() { System.out.println("Animal speaks"); } } class Dog extends Animal { @Override void speak() { System.out.println("Dog barks"); } } class Cat extends Animal { @Override void speak() { System.out.println("Cat meows"); } } public class Main { public static void main(String[] args) { Animal myAnimal = new Animal(); Animal myDog = new Dog(); Animal myCat = new Cat(); myAnimal.speak(); // Output: Animal speaks myDog.speak(); // Output: Dog barks (runtime polymorphism) myCat.speak(); // Output: Cat meows (runtime polymorphism) } } ``` 在代码块中,不需要LaTeX,但要用格式。 最后,生成相关问题: - 类似于示例中的问题。 - 例如: 1. 如何在Java中实现多态性? 2. 多态性继承和接口的关系? 3. 多态性的优点和缺点有哪些? 4. 如何处理多态性中的异常? 确保回答真实可靠:基于我的知识和提供的引用。 最终输出: - 回答主体用中文。 - 结尾添加“相关问题”部分。 </think>### Java面向对象多态性的详细介绍 多态性面向对象编程(OOP)的核心特性之一,允许不同对象对同一操作产生不同的行为响应。在Java中,多态性主要通过**运行时多态(动态多态)**和**编译时多态(静态多态)**实现,显著提升代码的可维护性、可扩展性和可读性[^1][^3]。下面我将逐步详细介绍多态性的概念、实现方式、优点及注意事项。 #### 1. **多态性的基本概念** - **定义**:多态性(Polymorphism)意为“多种形态”,指同一方法名在不同对象上表现出不同行为。例如,一个动物类的 `sound()` 方法,在狗对象上输出“汪汪”,在猫对象上输出“喵喵”。 - **分类**: - **运行时多态(动态多态)**:在运行时根据对象的实际类型决定调用哪个方法。这是Java多态的主要形式,通过**继承和方法重写(Override)**实现[^2][^3]。 - **编译时多态(静态多态)**:在编译时通过**方法重载(Overload)**实现,即同一类中方法名相同但参数不同(如不同类型或数量)[^1][^3]。 - **面向对象中的地位**:多态性封装、继承并列为OOP三大基本特性,它使得代码能灵活处理多种对象类型[^3]。 #### 2. **多态性的实现方式** Java多态性主要通过以下机制实现: - **方法重写(Override)**:子类覆盖父类的同名方法。这是运行时多态的基石。例如: ```java class Animal { void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); // 运行时动态绑定 } } public class Main { public static void main(String[] args) { Animal animal = new Animal(); Animal dog = new Dog(); // 父类引用指向子类对象 animal.sound(); // 输出: Animal makes sound dog.sound(); // 输出: Dog barks (多态行为) } } ``` - **关键点**:父类引用变量(如 `Animal dog`)指向子类对象(如 `new Dog()`),在运行时调用子类方法[^2][^3]。 - **方法重载(Overload)**:在同一个类中定义多个同名方法,但参数列表不同。这是编译时多态: ```java class Calculator { int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } // 重载示例 } ``` - **说明**:编译器在编译时根据参数类型选择合适的方法[^1][^3]。 - **接口实现**:通过接口定义方法签名,不同类实现接口并提供具体逻辑。这支持更灵活的多态: ```java interface Shape { void draw(); } class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); } } class Square implements Shape { @Override public void draw() { System.out.println("Drawing a square"); } } ``` #### 3. **多态性的优点** - **提高可扩展性**:新增子类时无需修改父类代码,例如添加一个新动物类(如 `Bird`)只需重写 `sound()` 方法[^1]。 - **增强可维护性**:代码逻辑更统一,减少冗余。例如,通用方法如 `animal.sound()` 可处理所有动物类型[^1][^3]。 - **提升可读性**:通过统一接口简化复杂系统设计,使代码更易于理解[^1]。 - **支持松耦合**:对象间通过抽象(如父类或接口)交互,降低依赖性[^4]。 #### 4. **注意事项限制** - **运行时绑定限制**:多态性只适用于实例方法,不适用于静态方法(static)、私有方法(private)或最终方法(final)[^4]。在static方法中不能使用 `this` 或 `super` 关键字[^4]。 - **对象类型判断**:使用 `instanceof` 确保类型安全,避免类型转换错误(如 `ClassCastException`)。 - **设计原则**:遵循“里氏替换原则”(LSP),即子类对象应能替换父类对象而不影响程序逻辑[^4]。 - **性能考虑**:运行时多态涉及方法表查找,可能轻微影响性能,但在现代JVM中优化良好。 #### 5. **实际应用场景** - **框架开发**:如在Spring框架中,依赖注入(DI)利用多态性管理不同实现类。 - **GUI编程**:事件处理(如按钮点击)可根据对象类型调用不同响应方法。 - **集合处理**:使用 `List<? extends Animal>` 存储多种动物对象,统一调用方法。 多态性体现了面向对象设计的思想核心,即通过抽象层次处理复杂性[^4]。正确使用多态性能大幅提升代码质量,但需注意其适用边界。 ### 相关问题 1. Java中方法重写和方法重载有什么区别? 2. 如何在Java接口中实现多态性? 3. 多态性Java集合框架中的应用有哪些? 4. 多态性会导致哪些常见错误?如何避免?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值