JAVA多态 向上转型 向下转型 抽象类 抽象方法 类与接口的关系 匿名内部类

多态 向上转型 向下转型 抽象类 抽象方法 类与接口的关系 匿名内部类

身边很多同学都说多态这部分是学java过程中遇到的第一个难点,里面很多抽象的内容很难理解。感觉这块还是得多看概念,不是所有代码学习都能只用通过大量代码练习才能学会,有时概念上的理解还先于实操。至于类,接口这里,则相反。

多态

面向对象编程有三大特性:封装、继承、多态

多态表示事物的多种形态

对象的多态性: 同一个对象,可能在不同的环境下,有不同的名称,不同的执行结果

譬如 我在学JAVA,对于学校来说我是学生,但回到家后我是儿子,出门对于社会来说我是百姓

多态的实现

多态实现的前提:

  • 要有父子类的继承关系

  • 方法的重写

  • 父类类型的引用指向子类对象

定义格式:

​ 父类类型 变量名=new 子类类型();

多态访问成员方法的特点

编译看左,运行看右

编译的时候,要看=左边的引用类型中,是否定义了该方法,如果有,就编译通过,如果没有就编译失败

运行的时候,要看= 右边,对象所属的类中,如果对这个方法进行实现,最终运行的是子类中对这个方法的实现

package Test2;
public class Tt {
	public static void main(String[] args) {
		Fu f = new Zi();//编译看左,父类中没有定义该方法(show()方法父类中有)
		f.show();//运行看右,看子类对该方法的实现("子类的show方法")
	}
}
class Fu{
	public void show() {
		System.out.println("父类的show方法");
	}
}
class Zi extends Fu{
	public void show() {
		System.out.println("子类的show方法");
	}
}

在这里插入图片描述

这里编译看左,Fu f 父类中存在和子类Zi一样的show()方法,所以编译通过

运行看右,Zi 子类中有对show()方法的实现,所以输出的是子类的方法实现


多态的转型

多态的转型分为向上转型和向下转型两种

向上转型

创建多态关系 (多态本身就是向上转型的过程)

使用父类的引用指向了子类对象

定义格式:父类类型 变量名=new 子类类型();

向上转型的本质:缩小了对象本身的访问范围,减少了他的访问权限,只访问父类中的内容

向下转型

让一个指向子类对象的父类引用,恢复成子类的引用

变量的强制转换

定义格式:

​ 子类类型 引用名称 = (子类类型)父类类型的引用

向下转型的本质:恢复子类对象的访问权限与范围

package Test2;
public class Tt {
	public static void main(String[] args) {
		Fu f = new Zi();//向上转型
		f.show();//缩小访问范围只能访问父类的内容
		f.fuwork();//父类中存在的方法子类若重写即可访问
		Zi z = (Zi)f;//向下转型:恢复本身的访问范围
		z.show();
		z.ziwork();
	}
}
class Fu{
	public void show() {
		System.out.println("父类的show方法");
	}
	public void fuwork() {
		System.out.println("只有父类有的方法");
	}
}
class Zi extends Fu{
	public void show() {
		System.out.println("子类的show方法");
	}
	public void ziwork() {
		System.out.println("只有子类有的方法");
	}
}

在这里插入图片描述

总结:父类类型的引用指向子类对象完成向上转型后,只能访问父类中的属性和方法,如果子类中没有这些方法和属性,是无法访问的,但子类要是重写了父类的某种方法,那调用时会实现子类的内容

多态的好处
  • 提高了代码的拓展性

  • 在方法中,如果形参是父类类型,调用这个方法时候,可以把这个父类类型的子类创建出来的对象,当做实参进行传递

  • 如果一个方法的返回值是父类类型,那么就可以在方法内将父类的子类对象,当做方法返回值返回,调用者可使用父类类型的引用来接收,或向下转型来接受都可

    package Test2;
    public class Tt {
    	public static void main(String[] args) {
    		Student stu = new Student();
    		stu.show(new Cat());实参  传递的是子类类型的对象
    		stu.show(new Dog());
    	}
    }
    class Student{
    	public void show(Pet p) {//形参 是父类类型的引用 
    		p.work();
    	}
    }
    class Pet{
    	public void work() {
    		System.out.println("工作");
    	}
    }
    class Cat extends Pet{
    	public void work() {
    		System.out.println("抓老鼠");
    	}
    }
    class Dog extends Pet{
    	public void work() {
    		System.out.println("看门");
    	}
    }
    

在这里插入图片描述

抽象类

抽象类

抽象:抽取像的,相同的或者相似的

可以定义抽象方法的类就是抽象类

1、抽象类的定义格式

​ abstract class 类名{

​ 类体;

​ }

如果父类中的方法被继承过去的子类都要重写 那就这个方法就没有在父类实现的意义了,可以直接定义为抽象类

抽象方法

抽象方法:被abstract修饰方法,被修饰后这个方法不会有具体实现,只能在抽象了的子类中通过方法重写进行实现,只有方法的声明,没有方法的实现,这种方法叫做抽象方法

抽象方法定义的格式:

​ 在方法的前面加上一个关键字:abstract

​ 因为没有方法的实现,不需要写大括号,

例如: public abstract void show();

package Test2;
public class Tt {
	public static void main(String[] args) {
		Wor wor = new Wor();
		wor.test1();
		wor.test2();
	}
}
abstract class Bos{//可以定义抽象方法的类,一定是抽象类
	public abstract void test1();//定义抽象方法
	public abstract void test2();
}
class Wor extends Bos{
	@Override
	public void test1() {//父类中的抽象方法,子类必须重写
		System.out.println("重写父类test1");
	}
	@Override
	public void test2() {
		System.out.println("重写父类test2");
	}
	
}

在这里插入图片描述

抽象类的特点

抽象类和抽象方法的关系

1、都要使用abstract关键字修饰

  • 抽象类中可以有抽象方法,也可以没有抽象方法

  • 抽象方法必须在抽象类中

  • 抽象类不能实例化,但可以定义抽象类子类,由子类去创建对象从而调用方法

2、抽象类的子类的分类

  • 如果子类实现了抽象类父类中的所有抽象方法,那这个类就是一个普通子类,就可以创建对象了

  • 如果子类,没有完全实现抽象类父类中的抽象方法,那这个子类还是一个抽象类,无法实例化

3、抽象类中可以定义成员变量和定义常量,但因为抽象类不能实例化,所以不能被抽象类使用,可以通过子类继承,访问父类的构造方法,来完成对抽象父类中成员变量的初始化,也可以有成员方法,这里定义的方法内容子类一般不会去重写

package Test2;
public class Tt {
	public static void main(String[] args) {
		Wor wor = new Wor();
		wor.test1();
	}
}
abstract class Bos{//可以定义抽象方法的类,一定是抽象类
	int age = 40 ;//定义成员变量
	final String name = "老板";//定义常量
	public abstract void test1();//定义抽象方法
	public Bos() {
		super();
	}
	public Bos(int age) {
		super();
		this.age = age;
	}
	public void eat() {//定义成员方法,一般是子类中不需要重写的内容
		System.out.println("吃大餐");
	}
	
}
class Wor extends Bos{
	@Override
	public void test1() {//父类中的抽象方法,子类必须重写
		System.out.println("重写父类test1");
	}
}

接口

是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口的好处:

  • 可以扩展一个事物的功能

  • 可以达到高内聚低耦合

  • 方便后期维护

接口在程序中的好处:

  • 规则的定义和规则的实现,分离

规则:对应的就是方法,都是抽象方法

实现者:对应的就是方法的具体实现,本质是一个对象

只需要说明应该有哪些方法,不需要管谁来实现了方法,实现了规则的定义和规则的实现分离

接口的格式

​ interface 接口名{

​ 方法的声明;

​ }

实现接口的方式:

定义类来实现接口,这个类就叫接口实现类

​ class 类名 implements 接口名{

​ 重写接口定义的所有抽象方法

​ }

package Test2;
public class Tt {
	public static void main(String[] args) {
		Person p = new Person();
		p.test();
		p.test1();
	}
}
interface Study {//定义接口
	public abstract void test();//定义规则,由子类去实现
	void test1();
}
class Person implements Study {//接口实现类,实现接口中的方法
	@Override
	public void test() {
		System.out.println("Person中重写的test方法");
	}

	@Override
	public void test1() {
		System.out.println("Person中重写的test1方法");
	}
}

在这里插入图片描述

接口的特点

  • 一个类如果实现了接口中的所有抽象方法,那么就是一个普通类,如果没有完全实现,就是一个抽象类
  • 接口中方法的声明,都是抽象方法,是一个抽象类型,不能实例化,只能定义实现类,实现接口,通过实现类创建对象,再由对象调用方法
  • 接口中定义的属性都默认前面 public static final,都是静态常量属性,所以就也没成员变量
  • 接口中没有成员变量,所以就不能定义构造方法
  • 接口中不能定义成员方法,只能定义抽象方法
package Test2;
public class Tt {
	public static void main(String[] args) {
		Student s = new Student();
		s.test();
		s.study();
	}
}
interface Book {//定义接口
	public abstract void test();//定义规则,由子类去实现
	void study();//这其实也是个抽象方法,默认public static final修饰
	//无成员变量,都是是静态常量属性,所以不能有构造方法
}
class Student implements Book {//接口实现类,实现接口中的方法
	@Override
	public void test() {
		System.out.println("Student中重写的test方法");
	}
	//如果一个接口中的方法,没有全部在子类中被重写,那么这个类就是一个抽象类
	//所以都必须重写
	@Override
	public void study() {
		System.out.println("Student中重写的study方法");
	}
}

类与接口的关系

类与类

使用extend继承,可以单继承,不可以多继承,可以多层继承

类与接口

类与接口使用implements实现,可以单实现,也可以多实现,不能多层实现

多实现的格式1:

​ class 类名 implements 接口1,接口2,接口3…{

​ 重写所有接口中的抽象方法

​ }

多实现没有安全隐患的,因为即使两个接口中有一样的抽象方法,但是类中,只需要提供一个实现就够了

多实现的格式2:

​ class 类名 extends 父类名 implements 接口1,接口2,接口3{
重写所有的抽象方法
}

package Test2;
public class Tt {
	public static void main(String[] args) {
	}
}
interface Book {
	public abstract void study1();
}
interface Journal {
	public abstract void study2();
}
interface Newspaper {
	public abstract void study3();
}
class Teacher{
	public void teach() {
		System.out.println("老师教书");
	}
}
class Student implements Book,Journal,Newspaper{//可以让一个实现类实现多个接口
	@Override
	public void study3() {
		System.out.println("Student中重写Book的方法");
		
	}

	@Override
	public void study2() {
		System.out.println("Student中重写Journal的方法");
	}

	@Override
	public void study1() {
		System.out.println("Student中重写Newspaper的方法");
	}
}
class Person2 extends Teacher implements Book,Journal{//可以继承一个类之后再实现多个接口

	@Override
	public void study2() {
		// TODO Auto-generated method stub
	}

	@Override
	public void study1() {
		// TODO Auto-generated method stub
	}
}
interface Book2 extends Book,Newspaper,Journal{
	//接口可以多继承
}
interface Book3 extends Book2{
	//接口可以多继承
}

匿名内部类

没有名字的内部类

适合创建那种只需要使用一次的类

使用前提:

  • 继承一个类

  • 实现一个接口

定义格式:

​ new 父类类名或者接口名(){

​ 父类方法的重写或者是接口内容的实现

​ }

本质:创建了一个子类对象、接口实现类对象

package Test2;
public class Tt {
	public static void main(String[] args) {
		new rest(){//接口实现类,可以理解为一个子类
			@Override
			public void eat() {
				System.out.println("吃零食");
			}
			@Override
			public void play() {
				System.out.println("打游戏");
			}
		}.play();
		//父类类型的引用指向子类对象
		//利用多态 把实现类对象赋值给父接口
		rest r = new rest() {
		//这里 rest 是父类类型    new rest(){}是子类对象
			@Override
			public void play() {
				System.out.println("吃零食~~~~~");
			}
			
			@Override
			public void eat() {
				System.out.println("打游戏~~~~~");
			}
		};
		r.eat();
		r.play();
	}
}
interface rest{
	public abstract void eat();
	public abstract void play();
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值