java对象的多态性

1. 定义

如果B类是A类的子类或间接子类,当用B类创建对象b并将这个对象b的引用赋给A类对象a时,如:
A a;
a = new B();
OR
A a;
B b = new B();
a = b;
则称A类对象a是子类B对象b的上转型对象。


2. 性质

对象b的上转型a的实体是有子类B创建的,但是上转型对象会失去子类B的一些属性和功能。上转型对象具有以下特点:
1.上转型对象不能操作子类新增加的成员变量,不能使用子类新增的方法。即为较子类B失去一些属性和功能,这些属性和功能是新增的。
2.上转型对象可以操作子类继承或隐藏的成员变量,也可以使用子类继承的或重写的方法。即为上转型对象可以操纵父类原有的属性和功能,无论这些方法是否被重写。
3.上转型对象调用方法时,就是调用子类继承和重写过的方法。而不会是新增的方法,也不是父类原有的方法。
可以将对象的上转型对象再强制转换到一个子类对象,强制转换过的对象具有子类所有属性和功能。


3. 举例

如:
OutputStream output;
output = new FileOutputStream(filename);


并且根据Java API知
java.lang.Object
  java.io.OutputStream

     java.io.FileOutputStream

这时,output就是上转型对象啦。有什么特殊呢?就是output可以使用FileOutputStream从父类OutputStream那里继承来的方法和重写的方法,而不能使用子类FileOutputStream自己新增的方法啦。最后,这种方法是很常用的哦。。。当父类有很多子类时,就能实现方法的多态。

多态中非静态成员方法的特点

  • 在编译时,参阅引用型变量所属的类中是否有调用的方法。如果有,则编译通过,如果没有没有则编译失败。
  • 在运行时,参阅对象所属的类中是否有调用的方法。
简单总结:成员方法在多态调用的时候编译时看左边,运行时看右边。

多态中静态成员方法的特点

编译和运行都看左边。

多态中成员变量的特点

无论编译或者运行的时候都看左边(引用型变量所属的类)。
/**
 * 多态中成员方法和成员变量的特点
 * 非静态成员方法:编译时看左边(父类),运行时看右边(子类)
 * 静态成员方法:编译和运行都参考左边(父类)
 * 成员变量:编译和运行都看左边(父类)
 */

class Fu{
	
	static int count = 100;	// 父类中的静态成员变量
	int num = 100;			// 父类中的非静态成员变量
	
	public void fun1(){
		System.out.println("父类中的fun1方法");
	}
	public void fun2(){
		System.out.println("父类中的fun2方法");
	}
	public static void fun4(){
		System.out.println("父类中的fun4静态方法");
	}
}

class Zi extends Fu{
	
	static int count = 0; 	// 子类中的静态成员变量
	int num = 0; 			// 子类中的非静态成员变量
	
	@Override
	public void fun1() {
		System.out.println("子类中的fun1方法,覆写了父类的fun1方法");
	}
	
	public void fun3(){
		System.out.println("子类中的fun3方法,此方法是子类特有的");
	}
	
	public static void fun4(){
		System.out.println("子类中的fun4静态方法");
	}
}

public class PolymorphismDemo {

	public static void main(String[] args) {
		
		Fu obj = new Zi();
		obj.fun1();	// 调用子类重写的方法,输出“子类中的fun1方法,覆写了父类的fun1方法”
		obj.fun2();	// 子类中没有重写fun2,则调用父类的fun2方法,打印“父类中的fun2方法”
//		obj.fun3();	//编译失败,因为父类中没有fun3方法,fun3方法是子类特有的
		obj.fun4();	// fun4是父类和子类都有的静态方法,打印“父类中的fun4静态方法”(因为Fu obj加载的是父类,静态不需要创建对象直接调用方法)
		
		System.out.println("obj.num = " + obj.num);		// 非静态成员变量编译和运行都看左边即num = 100
		System.out.println("obj.count = " + obj.count);	// 静态成员变量在类加载的是否确定值,看左边即count = 100
	}
}


对象的多态性

在对象实例化的时候A a = new B(),中满足B is-a A的关系(因为B extends A),而A a = new A(),中同样满足A is-a A的关系。

多态数组

abstract class Animal {
	public abstract void eat();

	public void sleep() {
		System.out.println("动物睡觉!");
	}
}

class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("我是狗,我吃肉!");
	}

}

class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("我是猫,我吃鱼");
	}

}

class Bird extends Animal {

	@Override
	public void eat() {
		System.out.println("我是鸟,我吃虫子。");
	}

}

public class Test {
	public static void main(String[] args) {
		/* 创建对象数组 */
		Animal[] animals = { new Dog(), new Cat(), new Bird() };
		for (Animal animal : animals) {
			animal.eat();
			animal.sleep();
		}
	}
}
运行结果:
我是狗,我吃肉!
动物睡觉!
我是猫,我吃鱼
动物睡觉!
我是鸟,我吃虫子。
动物睡觉!

对象的多态性中调用的是被子类覆写的方法。

方法参数的多态性

public class Test {
	public static void main(String[] args) {
		/* 创建对象数组 */
		Animal[] animals = { new Dog(), new Cat(), new Bird() };
		for (Animal animal : animals) {
			fun(animal);
		}
	}
	
	/*方法参数的多态*/
	public static void fun(Animal animal){
		animal.eat();
	}
}

运行结果:
我是狗,我吃肉!
我是猫,我吃鱼
我是鸟,我吃虫子。
执行各自的eat()方法。

如果程序编写的时候使用多态参数——也就是说将参数声明为父类类型,就可以在运行的时候传入子类对象。在以上的例子中如果别人写了一个Rabbit类,那么它就可以直接使用fun()方法,而不需要任何的修改。


Q1:你能够继承任何一个类么?

A1:继承中的一些限制:①存取控制(非public类)只能在同一个包中有子类;②final关键字修饰的类不能被继承;③构造方法私有化,没有子类。

方法覆写时应该遵循的规则:
①:方法的返回值和参数必须完全一样;
②:不能降低方法的访问权限。

方法的重载与多态毫无关系。(重载只是参数 不同)

一个抽象类除了被继承外没有任何其他作用。

为什么要有抽象方法?
将有方法体的方法放在父类中是一个好主意。但是有的时候就是没有办法给出对于任何子类都有意义的程序代码。抽象方法的意义就在于就算无法实现出方法的内容,但是也可以定义出一组子型共同的协议。这样做的好处就是多态。各个子类可以根据自己的需要去覆写父类中的抽象方法。
在继承树结构中的第一个具体类必须实现抽象类中的所有抽象方法。

Object类
public class Object,Object类是所有类的父类,是一个具体的类,常用的方法有:equals()、hashCode()方法、toString()方法和getClass()方法,强烈建议用自己的方法去覆盖原来的equals()、hashCode()方法和toString()方法。

Object类的两个目的:
1.作为多态让方法可以应付多种类型的机制。
2.提供java在执行期间对任何对象都有需要的方法的实现程序代码(让所有的类都会继承到)。有一部分的方法和线程有关。

<think>好的,我需要回答用户关于Java对象多态性的体现方式和示例的问题。首先,我应该回顾用户提供的引用内容,看看有哪些相关的信息可以利用。 根据引用[1],多态性是OOP的核心概念,允许同一接口在不同对象上有不同实现。引用[2]提到多态分为编译时多态(方法重载)和运行时多态(方法重写)。而用户特别关注的是对象多态性,这可能更偏向运行时多态,即通过继承和方法重写实现。 引用[4]指出,实现多态需要三个条件:继承、重写和向上转型。因此,示例需要展示这三个要素。比如,创建一个父类和子类,子类重写父类方法,然后通过父类引用指向子类对象,调用方法时实际执行子类的方法。 用户需要具体的示例,所以应该用代码来说明。比如,Animal类作为父类,Cat和Dog作为子类,重写eat方法。然后创建父类类型的变量指向子类实例,调用eat方法时会根据实际对象类型执行对应的方法,这就是运行时多态。 另外,引用[3]提到集合框架中的多态性,比如使用List接口引用ArrayList或LinkedList。可能可以加入这样的示例,展示多态在集合中的应用,比如List list = new ArrayList<>();,这里体现了接口的多态性。 需要注意的是,用户可能混淆了方法重载和对象多态。根据引用[2],方法重载是编译时多态,而用户的问题更关注对象多态,即运行时多态。因此,示例应侧重于继承和重写,而不是重载。 另外,可能需要解释向上转型的概念,即父类引用指向子类对象,这是实现多态的关键步骤。同时,多态的应用场景,比如在方法参数中接收父类类型,可以传入任何子类对象,增加代码的灵活性。 现在,组织这些思路,先定义多态性的体现方式,然后给出继承与重写的示例,接着是接口与实现类的示例,再结合集合框架的例子,最后总结多态的优势。确保每个示例都符合引用的内容,并在适当的地方添加引用标记。</think>### Java对象多态性的体现方式及示例 Java中的**对象多态性**主要通过**继承关系**和**方法重写**实现,具体表现为**父类引用指向子类对象**,并在运行时根据实际对象类型调用对应方法。其核心是**运行时绑定**(动态绑定)机制,满足以下三个条件:继承、重写、向上转型[^4]。 --- #### 一、多态性的典型体现 1. **方法重写(运行时多态)** 子类重写父类方法后,通过父类引用调用该方法时,实际执行的是子类的方法实现。 2. **向上转型(Upcasting)** 父类引用指向子类对象,例如:`Animal dog = new Dog();`。 3. **接口与实现类** 接口类型的引用可以指向不同实现类的对象,例如:`List list = new ArrayList<>();`。 --- #### 二、具体示例 ##### 示例1:继承与方法重写 ```java // 父类 class Animal { public void eat() { System.out.println("动物进食"); } } // 子类1 class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } // 子类2 class Dog extends Animal { @Override public void eat() { System.out.println("狗啃骨头"); } } public class Test { public static void main(String[] args) { Animal animal1 = new Cat(); // 向上转型 Animal animal2 = new Dog(); // 向上转型 animal1.eat(); // 输出:猫吃鱼(实际调用Cat类的方法) animal2.eat(); // 输出:狗啃骨头(实际调用Dog类的方法) } } ``` **说明**: - `Animal`类型的引用`animal1`和`animal2`分别指向`Cat`和`Dog`对象。 - 调用`eat()`方法时,JVM根据对象的实际类型决定执行哪个子类的方法[^2]。 --- ##### 示例2:接口多态性 ```java interface Shape { void draw(); } class Circle implements Shape { @Override public void draw() { System.out.println("绘制圆形"); } } class Rectangle implements Shape { @Override public void draw() { System.out.println("绘制矩形"); } } public class Test { public static void main(String[] args) { Shape shape1 = new Circle(); Shape shape2 = new Rectangle(); shape1.draw(); // 输出:绘制圆形 shape2.draw(); // 输出:绘制矩形 } } ``` **说明**: - 接口`Shape`的引用可以指向不同实现类对象,调用`draw()`时体现多态性[^3]。 --- ##### 示例3:集合框架中的多态性 ```java List<String> list = new ArrayList<>(); // 接口引用指向ArrayList list.add("Java"); list = new LinkedList<>(); // 同一接口引用切换为LinkedList list.add("Python"); ``` **说明**: - 通过`List`接口统一操作不同实现类(如`ArrayList`和`LinkedList`),代码更灵活[^3]。 --- #### 三、多态性的优势 1. **代码扩展性**:新增子类时无需修改原有代码(如新增`Bird extends Animal`)。 2. **统一接口**:通过父类或接口统一处理不同子类对象。 3. **降低耦合**:调用方仅依赖抽象层(父类/接口),不依赖具体实现。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值