15k字全面讲解Java面向对象程序三大特性(封装,继承,多态)

一: 封装

1.1 概念

封装是面向对象编程的核心思想.
将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现的细节,这就是封装的思想.
举一个简单的例子:用户使用计算机时,只需要用鼠标或者键盘就可以实现一些功能,不需要知道计算机内部是怎样工作的.
采用封装的思想保证了类内部的数据结构的完整性,应用该类的用户不能轻易的直接操作此数据结构,只能执行类允许公开的数据,这样就避免了外部操作对内部数据的影响,提高了程序的可维护性.

使用类实现封装特性如下图所示:
封装特性示意图

1.2 封装扩展之包

1.2.1 包的概念.

在面向对象体系中,为了更好的管理类,把多个类收集在一起成为一组,称为软件包.
在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。
包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。

如下图,这是我自己平时写代码时创建的不同的包.每个包中都有许多的类
在这里插入图片描述

1.2.2 类名冲突

如果没有包的存在,管理程序中的类名称将是一种非常麻烦的事情.如果程序只由一个类组成,并不会给程序带来多大的影响,但是随着程序代码的增多,难免会出现同类名的问题.例如,在程序中定义一个Student的类,因为需求的关系,还需要一个Student类,但是这两个类所实现的功能完全不同,于是就会产生类名冲突的问题—编译器不允许存在同名的类文件.
解决这类问题的办法就是将这两个类放置在不同的包中.

1.2.3 导包

a.使用import关键字进行导包.
Java中已经提供了很多现成的类供我们使用.例如Date类:

import java.util.Date;
public class TestDate{
    
    
	//Date包中自带的类,我们导包之后可以使用
	Date d=new Date();
	//得到一个毫秒级别的时间戳
	System.out.println(date.getTime());
}

如果需要使用java.util中的其他类,可以使用import java.util.*; *的意思是所有.
但是我们更建议导入指定的类名,否则可能会出现冲突的情况.

import java.util.*;
import java.sql.*;
public class Test {
    
    
 	public static void main(String[] args) {
    
    
	 // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
 	Date date = new Date();
 	System.out.println(date.getTime());
 	}
}

b.使用import导入静态成员变量
import关键字除了导入包之外,还可以导入静态成员变量,可以使编程更加简单.
语法:

import static 静态成员

我们来看示例:

import static java.lang.Math.max;
import static java.lang.System.out;
public class Test{
    
    
	public static void main(String[] args){
    
    
		//在主方法中直接使用这些静态成员.
		out.println("1和2中的较大值为:"+max(1,2));
	}
}

//输出结果
12中的较大值为:2

1.2.4 认识一些常见的包

  1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

1.3 访问限定符

Java中的权限修饰符主要包括private,protected,public,default是默认权限修饰符,这些修饰符控制着对类和类的成员变量以及成员方法的访问.
我们分为三部分进行介绍.

1.3.1 表格介绍

在这里插入图片描述

1.3.2 文字介绍

1.private(只有自己知道,其他人都不知道)
如果一个类的成员变量或者成员方法被private修饰,则该成员变量只能在本类中使用,在子类中是不可见的,并且对其他包的类也是不可见的.
2.public(可以理解为一个人的外貌特征,谁都可以看到)
如果一个类的成员变量或者成员方法被public修饰,那么除了在本类中可以使用这些数据外,还可以在子类和其他包的类中使用.
3.protected(主要用于继承中)
如果一个类的成员变量或者成员方法被protected修饰,那么只有本包内的该类的子类或其他类可以访问此类中的成员变量和成员方法.
4.default(对于自己家人(一个包中)来说不是秘密,对其他人就是隐私了)
默认修饰符,如果一个类的成员变量或者成员方法没有被任何修饰符修饰,那么就会默认使用default修饰符.只能在本包中类访问.

从上面可以看出,如果一个类的访问权限是被设置为private,这个类将隐藏其内的所有数据,以免用户直接访问它.如果需要使类中的数据被子类或者其他包中的类使用,可以将这个类设置为public访问权限.如果父类不允许通过继承产生的子类访问他的成员变量,那么必须使用private声明父类的这个成员变量.
访问权限的高低为 public > default >protected > private

1.3.3 用代码来理解

// extend01包中.
public class A {
    
    
 	private int a;
 	protected int b;
 	public int c;
 	int d; 
}
// extend01包中.
// 同包中的子类.
public class D extends A{
    
    
 	public void method(){
    
    
 		// super.a = 10; 	编译报错,父类private成员在相同包子类中不可见
 		super.b = 20; // 父类中protected成员在相同包子类中可以直接访问
 		super.c = 30; // 父类中public成员在相同包子类中可以直接访问
		super.d = 40; // 父类中默认访问权限修饰的成员在相同包子类中可以直接访问
 	}
 }
 
// extend02包中.
// 不同包中的子类.
public class C extends A {
    
    
 	public void method(){
    
    
    // super.a = 10;
    super.b = 20; // 父类中protected修饰的成员在不同包子类中可以直接访问
 	super.c = 30; // 父类中public修饰的成员在不同包子类中可以直接访问
 	//super.d = 40; // 父类中默认访问权限修饰的成员在不同包子类中不能直接访问
 	}
}
 
// extend02包中
// 不同包中的类
public class TestC {
    
    
 	public static void main(String[] args) {
    
    
 		C c = new C();
 		c.method();
 		
 		// 编译报错,父类中private成员在不同包其他类中不可见
 		// System.out.println(c.a); 
 		
 		// 父类中protected成员在不同包其他类中不能直接访问
 		// System.out.println(c.b); 
 		
 		// 父类中public成员在不同包其他类中可以直接访问
		System.out.println(c.c); 
		
		// 父类中默认访问权限修饰的成员在不同包其他类中不能直接访问
 		// System.out.println(c.d); 
	}
}

二:继承

2.1 为什么要使用继承

当处理问题时,可以将一些有用的类保留下来,在遇到同样的问题时拿来复用.
面向对象中提出的继承的概念,专门用来进行共性抽取,实现代码复用.

2.2 概念和机制

关联: 类与类之间同样具有关系,这种关系被称为关联.关联主要描述两个类之间的一般二元关系,例如,商场类和销售员类就是一个关联,学生与老师也是一个关联.两个类之间的关系有很多种,继承就是关联中的一种.
继承机制: 是面向对象程序设计使代码可以复用的最重要的手段,它允许程序在保持原有类特性的基础上进行扩展,增加新的功能,这样产生新的类,成为派生类,也叫子类.原有的类叫基类,也叫父类.
我们来举一个动物的例子, 就用最常见的猫和狗来说.
我们定义一个动物类Animal(基类), Cat类和Dog类(派生类) 都继承它.
猫和狗都有共同的特征,比如,eat,sleep,name,age等等.也有不同的特征,比如叫声不同,而这项特征就需要在各自的类中去扩展了.

我们来用一个图来看看各自的关系.
在这里插入图片描述

2.3 继承的语法

在Java中如果需要表示继承关系时,需要借助extends关键字.

修饰符 class 子类 extends 父类{
    
    
	//...
}

我们来把2.2中的例子进行模拟实现一下.

//Animal.java
public class Animal{
    
    
	String name;
	int age;
	
	public Animal(){
    
    }
	public void eat(){
    
    
		System.out.println(name+"正在吃饭!");
	}
	public void sleep(){
    
    
		System.out.println(name+"正在睡觉!");
	}
} 

//Dog.java
public class Dog extends Animal{
    
    
	public Dog(){
    
    }
	void bark(){
    
    
		System.out.println(name+"旺!旺!旺!");
	}
}

//Cat.java
public void Cat extends Animal{
    
    
	public Cat(){
    
    }
	void mew(){
    
    
		System.out.println(name+"喵!喵!喵!");
	}
}

//Test.java
public class Test{
    
    
	public static void main(String[] args){
    
    
		Dog d=new Dog();
		//我们在Dog类中没有定义任何的成员变量,
		//所以这里的name,age肯定是从Animal类中继承的
		d.name="小黄";
		d.age=3;
		System.out.println(d.name);
        System.out.println(d.age);
        //eat()和sleep()方法也是从Animal类中继承的
        //而bark()方法是自己类中定义的.
        d.bark();
        d.eat();
        d.sleep();
        System.out.println("+++++++++++++++");
        //与上述同理
        Cat c=new Cat();
        c.name="小花";
        c.age=2;
        System.out.println(c.name);
        System.out.println(c.age);
        c.mew();
        c.eat();
        c.sleep();
	}
}
输出结果:
小黄
3
小黄 旺!!!
小黄 正在吃饭!
小黄 正在睡觉!
+++++++++++++++
小花
2
小花 喵!!!
小花 正在吃饭!
小花 正在睡觉!

注意:
1.子类会将父类中的成员变量或者方法都继承到了自己类中
2.在继承父类后,必须对自己类的内容进行扩展,体现出与父类的不同,否则就没必要继承了.

2.4 父类成员访问

2.4.1 子类中访问父类中的成员变量

a. 子类和父类不存在同名成员变量

public class Base{
    
    
	int a;
	int b;
}
public class Derived extends Base{
    
    
	int c;
	public method(){
    
    
		a=10;		//继承自父类
		b=20;		//继承自父类
		c=30;		//自己的成员变量
	}
}

b.子类和父类成员变量同名

public class Base{
    
    
	int a;
	int b;
	int c;
}
public class Derived extends Base{
    
    
	int a;		//同名同类型
	char b;		//同名不同类型
	public method(){
    
    
		a=10;		//继承自父类
		b=20;		//自己的成员变量
		c=30;		//继承来自父类
	}
}

在子类方法中 或者 通过子类对象访问成员时:
a.如果访问的成员变量子类中有,优先访问自己的成员变量。
b.如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
c.如果访问的成员变量与父类中成员变量同名,则优先访问自己的,即:子类将父类同名成员隐藏了。
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找.

2.4.2 子类中访问父类的成员方法

a.成员方法名字不同

成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中查找,如果父类中也没有则会报错.

public class Base{
    
    
	public void methodA(){
    
    
		System.out.println("Base中的methodA()方法");
	}
}
public class Derived extends Base{
    
    
	//与父类中的方法构成重载.
	public void methodB(){
    
    
		System.out.println("Derived中的methodB()方法");
	}
	public void methodC(){
    
    
		methodA();		//继承自Base类的methodA方法.
		methodB();		//自己类中的menthodB方法.
	}
}

b.成员方法名字相同

通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类同名方法的原型一致(重写),则只能访问到子类的,父类的无法通过派生类对象直接访问到。

public class Base{
    
    
	public void methodA(){
    
    
		System.out.println("Base中的methodA()方法");
	}
	public void methodB(){
    
    
		System.out.println("Base中的methodB()方法");
	}
}
public class Derived extends Base{
    
    
	public void methodA(int a){
    
    
		System.out.println("Derived中的methodA(int)方法");
	}
	//和父类中的方法同名
	public void methodB(){
    
    
		System.out.println("Derived中的methodB()方法");
	}
	public void methodC(){
    
    
		//没有参数,继承自父类中的方法
		methodA();
		//带有参数,自己类中的方法			
		methodA(20);		
		//直接访问,则永远都是访问到自己类中的方法,父类的无法访问到.
		methodB();			
	}
}

那么在这里问题来了,如果子类中存在和父类同名的方法,我们应该怎样在子类中访问父类的方法呢?
答案是使用super关键字。

2.5 super关键字

由于场景需要,子类和父类中可能存在相同名称的成员,显然直接访问是无法做到的,在Java中提供了super关键字。
作用就是在子类中访问父类中的成员。

2.6 super关键字的使用

2.6.1 调用成员方法和成员变量

创建父类.

public class Base(){
    
    
	int a;
	int b;
	public void methodA(){
    
    
		System.out.println("Base---methodA()");
	}
	public void methodB(){
    
    
		System.out.println("Base---methodB()");
	}
}

用子类进行继承

public class Derived extends Base{
    
    
	int a;
	char b;
	//与父类中的methodA构成重载
	public void methodA(int a){
    
    
		System.out.println("Derived---methodA(int)");
	}
	//与父类中的methodB构成重写
	public void methodB(){
    
    
		System.out.println("Derived---methodB()");
	}
	public void methodC(){
    
    
		//本类中的成员
		a=100;
		b=101;
		//super关键字调用父类中的成员
		super.a=200;
		super.b=201;
		
		methodA(100);		//调用子类中的methodA()方法,有参数
		methodA();			//从父类中继承的methodA()方法,无参数
		
		methodB();			//默认调用子类中的methodB()方法,无参
		//这里如果写methodB(),肯定会调用子类自己的方法.
		super.methodB();	//用super.调用父类中的methodB()方法
	}
	public class void main(String[] args){
    
    
		Derived d=new Derived ();
		d.methodC();
		/*
			输出结果:
			Derived---methodA(int)
			Base---methodA()
			Derived---methodB()
			Base---methodB()
		*/
	}
}

在子类方法中或者子类对象访问成员时,优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。
注意:只能在非静态的方法中使用.

//编译时会报错.
public static void error(){
    
    
	super.a=300;
	super.methodA();
}

2.6.2 调用构造方法.

子类对象构造时,需要先调用父类的构造方法,然后执行子类的构造方法.(这句话其实不严谨),先看代码,后文中解释.

public class Base{
    
    
	public Base(){
    
    
		System.out.println("Base()");
	}
}

子类继承父类.

public class Derived extends Base{
    
    
 	public Derived(){
    
    
 	// super();
 	/*
		注意:子类构造方法中默认会调用基类的无参构造方法:super(),
 	 	用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
 	 	并且只能出现一次.
	*/
 		System.out.println("Derived()");
 }
}

测试类

public class Test {
    
    
 	public static void main(String[] args) {
    
    
 	Derived d = new Derived();
 	}
}
运行结果:
 Base()
 Derived()

从运行结果来看,确实是父类构造方法先于子类构造方法执行.
其实,创建对象的时候,先调用的是子类的构造方法,但是子类的构造方法中会用super()调用父类中的无参构造方法,并且super()永远处于第一行.所以运行结果会出现先Base(),再Derived().

2.7 继承方式

在Java中支持的继承方式有:单继承,多层继承,不同类继承同一个类。
Java中不支持多继承的方式。

单继承图解:在这里插入图片描述
多层继承图解:
在这里插入图片描述
不同类继承同一个类:
在这里插入图片描述
多继承(Java中不支持):
在这里插入图片描述

注意:
1.我们并不希望类之间的继承层次太复杂,一般我们不希望出现超过三层的继承关系。
2.super只在代码层面中可以体现出来,告诉编译器访问基类的成员,但是实际在底层,是没有super的.

2.8 继承的作用

1.实现代码的复用

实现代码复用的缺点:
a.破坏了类的封装性
b.子类和父类的耦合性太高.
父类中某个方法发生了改变,子类一定会看到改变,
父类中某个方法多加了一个参数,子类调用该方法的函数都需要修改.
一般不会推荐使用继承来实现代码的复用.
c.子类除了构造方法没有继承下来外,其他成员都继承到子类中了.
2.在继承体系下可以实现多态.

2.9 继承与组合的区别:

继承:父类和子类是is-a的关系,即:一个子类对象可以看成是一个父类对象,比如:
狗是动物
组合:对象和对象之间是has-a的关系,可以在一个对象内包含另外一个对象,比如:
汽车包括轮胎,方向盘,车载等等,但是不能说轮胎是一辆汽车.

三:多态

3.1 概念

1.通俗来说,多态就是多种形态.
2.具体点就是去完成某个行为,当不同的对象去完成时会产生不同的状态.
3.将父类对象应用于子类的特征就是多态.

我们来以一个例子进行说明:
以图形类举例,每个图形都拥有绘制自己的能力,这个能力可以看作是该类具有的行为,如果将子类的对象统一看作是父类的实例对象,这样当绘制图形时,简单的调用父类也就是图形类绘制图形的方法即可绘制任何图形,这就是多态的基本思想.

再通俗一点:对于同一行为,不同的子类对象有不同的表现,如:动物吃食物,猫吃鱼,狗吃骨头.

3.2 分类

静态多态(早绑定)
概念:在程序编译阶段,已经确定了方法的具体行为,即:已经确定了具体要调用哪个方法.
典型的代码-----方法重载

public class A{
    
    
	public void method(){
    
    
		System.out.println("method()");
	}
	public void method(int a){
    
    
		System.out.println("method(int)");
	}
	public static void main(String[] args){
    
    
		A a=new A();
		a.method();
		a.method(5);
	}
}

动态多态(晚绑定)
概念:即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体
调用那个类的方法。
典型的代码-----方法重写.
在3.4部分中含有相关代码.

3.3 重写

3.3.1 概念

重写也称为覆盖.重写是子类对父类非静态,非private修饰,非final修饰,非构造方法等的实现过程进行重新编写,返回值和形参都不能改变,即外壳不变,核心重写.

3.3.2 方法重写的规则:

a. 子类在重写父类的方法时,一般必须与父类方法原型一致:修饰符 返回值类型 方法名(参数列表) 要完全一致
b. JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected.
c. 父类被static、private修饰的方法、构造方法都不能被重写。
d. 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
e. 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
f. 将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写.
g. 一定是子类对父类的方法进行重写

3.3.3 重载与重写的区别

区别点 重载(overload) 重写(override)
参数列表 必须修改 一定不能修改
返回值类型 可以修改 一般都是相同的
访问限定符 可以修改 一般都是相同的
方法限制 没有限制 构造,privatefinal,static修饰的都不能被重写
方法定义范围 没有范围 一个方法必须在基类另一个方法必须在子类中

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现.

3.4 实现多态的条件

1.必须在继承的体系下才能完成
2.子类必须要对父类想要实现多态的方法进行重写–子类必须要对父类的方法进行重写
3.对重写的方法调用:只能通过父类的引用去调用被重写方法
多态体现:在程序执行时根据父类引用引用不同类的对象,就会调用对应类中被重写的方法

代码测试:

//Animal类
public class Animal{
    
    
	String name;
	int age;
	public Animal(String name,int age){
    
    
		this.name=name;
		this.age=age;
	}
	//实现多态行为
	public void eat(){
    
    
		System.out.println("吃饭");
	}
}
//Cat类继承Animal类.
public class Cat extends Animal{
    
    
	public Cat(String name,int age){
    
    
		//调用父类的构造方法
		super(name,age);
	}
	//重写父类方法
	public void eat(){
    
    
		System.out.println(name+": 正在吃鱼");
	}
}
//Dog类继承Animal类.
public class Dog extends Animal{
    
    
	public Dog(String name,int age){
    
    
		//调用父类的构造方法
		super(name,age);
	}
	//重写父类方法
	public void eat(){
    
    
		System.out.println(name+": 正在吃骨头");
	}
}
//测试类
public class Test{
    
    
	//父类引用去调用被重写的方法.
	public static void eat(Animal a){
    
    
		a.eat();
	}
	public static void main(String[] args){
    
    
		Cat c=new Cat("元宝",2);
		Dog d=new Dog("小七",1);
		eat(c);
		eat(d);
	}
}
输出结果:
元宝正在吃鱼
小七正在吃骨头

3.5 向上转型和向下转型

3.5.1 向上转型

实际上就是创建一个子类对象,将其当作是父类对象来使用.
语法格式: 父类类型 对象名 = new 子类类型();

//猫一定是动物.
Animal a=new Cat("元宝",1);

在这里插入图片描述

Animal 是一个父类类型,但是可以引用一个子类对象,因为:子类对象是一个父类对象,即可以将一个子类对象当作父类对象来用,因为是从小范围往大范围转换,因此:向上转型是安全的.

使用场景:

a.直接赋值
b.方法传参
c.方法返回值

//Animal
public class Animal{
    
    
	String name;
	int age;
	public Animal(String name,int age){
    
    
		this.name=name;
		this.age=age;
	}
	public void eat(){
    
    
		System.out.println("吃饭");
	}
}
//Dog
public class Dog extends Animal{
    
    
	public Dog(String name,int age){
    
    
		super(name,age);
	}
	public void eat(){
    
    
		System.out.println(name+": 正在吃骨头");
	}
	public void bark(){
    
    
		System.out.println(name+"旺!旺!旺!");
	}
}
//Cat
public void Cat extends Animal{
    
    
	public Cat(String name,int age){
    
    
		super(name,age);
	}
	public void eat(){
    
    
		System.out.println(name+": 正在吃鱼");
	}
	public void mew(){
    
    
		System.out.println(name+"喵!喵!喵!");
	}
}
//测试类
public class TestAnimal{
    
    
	// b.方法传参: 形参为父类型引用,可以接受任意子类对象
	public static void eat(Animal a){
    
    
		a.eat();
	} 
	//c.作为返回值: 返回任意子类对象
	public static Animal buyAnimal(String name){
    
    
		if(name.equals("狗")){
    
    
			return new Dog("小七",1);
 		}else if(name.equals("猫")){
    
    
 			return new Cat("元宝",2);
 		}else{
    
    
 			return null;
 		}
	}
	public static void main(String[]	args){
    
    
		//a.直接赋值: 子类对象赋值给父类对象
		Animal cat=new Cat("汤圆",1);
		Dog dog=new Dog("小七",1);
		
		eat(cat);
		eat(dog);
		//返回值是一个对象
		Animal a1=buyAnimal("狗");
		a1.eat();
		//编译器在编译阶段,会将a1识别成Animal的这种类型
		//所有通过a1调用的方式,都会在Animal类当中去查找.
		//a1.bark();此处会编译错误.
		//但是实际上a1指向的是一个Dog的对象
		//我们使用强制类型转换
		Dog d=(Dog)a1;
		d.bark();
		Animal a2=buyAnimal("猫");
		a2.eat();
		//a2.mew();
	}
}

优点: 让代码实现更简单灵活
缺点:不能调用到子类特有的方法

3.5.2 向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法.
此时:将父类引用再还原为子类对象即可,即向下转换。

在这里插入图片描述

//测试类:
public class TestAnimal{
    
    
	public static void main(String[]	args){
    
    
		Cat cat = new Cat("元宝",2);
 		Dog dog = new Dog("小七", 1);
 		//向上转型
 		Animal a1 = dog;
 		a1.eat();
 		//a1.bark();
 		Animal a2 = cat;
 		a2.eat();
 		
 		/*
 			编译器在编译阶段,会将a1识别成Animal的这种类型
			所有通过a1调用的方式,都会在Animal类当中去查找.
			a1.bark();此处会编译错误.
			但是实际上a1指向的是一个Dog的对象
			在这里使用强制类型转换,将a1转换为Dog对象.
			向下转型(不推荐下面方式来进行转化)
		*/
		Dog d=(Dog)a1;
		d.bark();
		//抛出类型转换异常(ClassCastException),a1是一个狗的对象,不能将狗强制转换为猫.
		//Cat c=(Cat)a1;
	}
}

向下转型用的比较少,而且不安全,万一转换失败,就会抛异常.而在Java中,为了提高向下转型的安全性,引入了instanceof关键字.如果表达式为true,则可以安全转换.
instanceof 关键字用来对比左边的对象是否属于右边的对象

//如果a1是Dog类型的对象,则可以进行转化.
if(a1 instanceof Dog){
    
    
	Dog d=(Dog) a1;
	d.bark();
}
//如果a2是Cat类型的对象,则可以进行转化.
if(a2 instanceof Cat){
    
    
	Cat c=(Cat) a2;
	c.mew();
}

写到这里,关于三大特性就介绍完了,如果哪里有错误欢迎各位来指正,谢谢!

猜你喜欢

转载自blog.csdn.net/weixin_47278183/article/details/121888439
今日推荐