《Java编程思想》笔记05——多态

《Java编程思想》笔记05——多态

大家好,又见面了,我是全栈君。

一、再论向上转型

/** * 向上转型 * @author LiangYu * 2018-01-09 */
public class UpCastTest {
	@Test
	public void test() throws Exception {
		Draw draw = new Draw();
		drawBlue(draw);
	}
	
	public void drawBlue(Art art){
		art.paint("blue");
	}
}

class Art{
	public void paint(String color){
		System.out.println("Art paint()---->"+color);
	}
}

class Draw extends Art{
	@Override
	public void paint(String color) {
		System.out.println("Draw paint()---->"+color);
	}
}
复制代码

在drawBlue()接受一个Art类的引用,同时,它也可以接受一个Art的子类引用。因此,当传入Draw类的引用时,该方法也可以执行。因为,Draw类是从Art类继承而来的,Art类的接口必然存在于Draw中,从Draw类向上转型会缩小接口,但接口不会比Art类更窄。

向上转型,实际上就是从特殊到普通的过程。

例如:鱼是动物的子类,就具备动物的所有特征。但并不是所有动物都具备鱼的特征

二、多态

方法调用绑定: 将一个方法调用同一个方法主体关联起来。

前期绑定:编译时绑定

如果Java采用前期绑定,则即使传入Draw的引用,程序也不清楚究竟要执行Draw的paint方法还是执行Art的paint方法。

因此,Java通常会采用后期绑定。

后期绑定:运行时绑定

编译器一直都不知道对象的类型,但是方法调用机制能够找到正确的方法体,并加以调用。即:运行时根据对象的类型进行绑定。

特例:Java中,static、final、private修饰的方法会进行前期绑定

/** * 多态 * @author LiangYu * 2018-01-09 */
public class PolymorphismTest {
	@Test
	public void test() throws Exception {
		Shape shape1 = new Circle();
		Shape shape2 = new Square();
		shape1.draw();
		shape2.erase();
	}
}

class Shape{
	public void draw(){
		System.out.println("shape draw");
	}
	
	public void erase(){
		System.out.println("shape erase");
	}
}

class Circle extends Shape{
	@Override
	public void draw() {
		System.out.println("circle draw");
	}
	
	@Override
	public void erase() {
		System.out.println("circle erase");
	}
}

class Square extends Shape{
	@Override
	public void draw() {
		System.out.println("square draw");
	}
	
	@Override
	public void erase() {
		System.out.println("square erase");
	}
}
复制代码

三、多态的缺陷

1.“覆盖”私有方法

/** * 多态的缺陷1 ----- “覆盖”私有方法 * @author LiangYu * 2018-01-09 */
public class PrivateMethodTest {
	
	private void privateMethod(){
		System.out.println("parent");
	}
	
	@Test
	public void test() throws Exception {
		PrivateMethodTest test = new Child();
		test.privateMethod();
	}
}

class Child extends PrivateMethodTest{
	public void privateMethod(){
		System.out.println("child");
	}
}
复制代码

输出结果: parent

结论:

只有非private方法才可以被覆盖

在子类中,对于基类的private方法,最好采用不同的名字。

2.域和静态方法

/**
 * 域和静态方法的多态
 * @author LiangYu
 * 2018-01-09
 */
public class FieldAndStaticMethodTest {
	@Test
	public void test() throws Exception {
		Person person = new Student();
		System.out.println(person.id);
		System.out.println(person.getId());
		person.toText();
		
	}
}


class Person{
	public String id = "p007";
	public String getId(){
		return id;
	}
	public static void toText(){
		System.out.println("Person");
	}
}

class Student extends Person{
	public String id = "s005";
	public String getId(){
		return id;
	}
	public static void toText(){
		System.out.println("Student");
	}
}
复制代码

输出结果:

p007

s005

Person

结论:

域访问操作是由编译器解析,不是多态

静态方法是前期绑定,也不是多态

四、构造器和多态

构造器本身是不具备多态性的。因为:它们实际上是隐式的static方法

基类构造器总是在子类的构造过程中被调用

原因:

子类只能访问自己的成员,无法访问基类成员(基类成员通常是private类型)。只有基类的构造器才有恰当的权限来对自身的成员进行初始化,所以,必须要让所有的构造器都得到调用。

/** * 构造方法的初始化顺序 * @author LiangYu * 2018-01-09 */
public class OrderOfConstructorTest extends FootballManager {
	private Movie movie = new Movie();
	private Music music = new Music();
	@Test
	public void test() throws Exception {
	}
	public OrderOfConstructorTest() {
		System.out.println("OrderOfConstructorTest()");
	}
}

class Game{
	Game(){
		System.out.println("Game()");
	}
}

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

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

class ComputerGame extends Game{
	public ComputerGame() {
		System.out.println("ComputerGame()");
	}
}

class FootballManager extends ComputerGame{
	public FootballManager(){
		System.out.println("FootballManager()");
	}
}
复制代码

运行结果:

Game()

ComputerGame()

FootballManager()

Movie()

Music()

OrderOfConstructorTest()

复杂对象调用构造器的顺序:

1.首先调用基类构造器,例如上面的示例中,根据Game->ComputerGame->FootballManager->OrderOfConstructorTest的四层结构,依次调用了Game()、ComputerGame()、FootballManager()

2.按照声明顺序调用成员的初始化方法。在上面的示例中: 依次调用:Movie()、Music()

3.调用子类的构造器主体:OrderOfConstructorTest()

继承与清理

应用组合和继承方法来创建新类时,永远不必担心对象的清理问题。子对象通常都会留给垃圾回收器进行处理。

如果确实遇到了清理问题,则需要为新类创建dispose()方法。由于继承的缘故,需要在子类覆盖dispose(),当覆盖dispose()时,还需要调用基类的dispose()。

/** * 继承与清理 * @author LiangYu * 2018-01-09 */
public class CleanTest{
	@Test
	public void test() throws Exception {
		JavaProgrammer javaProgrammer = new JavaProgrammer();
		System.out.println("Bye");
		javaProgrammer.dispose();
	}
}

class Eye{
	private String string;
	public Eye(String string) {
		this.string = string;
		System.out.println("Eye creating..."+string);
	}
	protected void dispose(){
		System.out.println("Eye disposing:"+this.string);
	}
}

class Ear{
	private String string;
	public Ear(String string) {
		this.string = string;
		System.out.println("Ear creating..."+string);
	}
	protected void dispose(){
		System.out.println("Ear disposing:"+this.string);
	}
}

class People{
	private Eye eye = new Eye("People Eye");
	private Ear ear = new Ear("People Ear");
	public People() {
		System.out.println("People()");
	}
	protected void dispose(){
		System.out.println("People disposing...");
		ear.dispose();
		eye.dispose();
	}
}

class Farmer extends People{
	private Eye eye = new Eye("Farmer Eye");
	private Ear ear = new Ear("Farmer Ear");
	public Farmer() {
		System.out.println("Farmer()");
	}
	protected void dispose(){
		System.out.println("Farmer disposing...");
		ear.dispose();
		eye.dispose();
		super.dispose();
	}
}

class SoftwareProgrammer extends Farmer{
	private Eye eye = new Eye("SoftwareProgrammer Eye");
	private Ear ear = new Ear("SoftwareProgrammer Ear");
	public SoftwareProgrammer() {
		System.out.println("SoftwareProgrammer()");
	}
	protected void dispose(){
		System.out.println("SoftwareProgrammer disposing...");
		ear.dispose();
		eye.dispose();
		super.dispose();
	}
}

class JavaProgrammer extends SoftwareProgrammer{
	private Eye eye = new Eye("JavaProgrammer Eye");
	private Ear ear = new Ear("JavaProgrammer Ear");
	public JavaProgrammer() {
		System.out.println("JavaProgrammer()");
	}
	protected void dispose(){
		System.out.println("JavaProgrammer disposing...");
		ear.dispose();
		eye.dispose();
		super.dispose();
	}
}
复制代码

运行结果:

Eye creating…People Eye

Ear creating…People Ear

People()

Eye creating…Farmer Eye

Ear creating…Farmer Ear

Farmer()

Eye creating…SoftwareProgrammer Eye

Ear creating…SoftwareProgrammer Ear

SoftwareProgrammer()

Eye creating…JavaProgrammer Eye

Ear creating…JavaProgrammer Ear

JavaProgrammer()

Bye

JavaProgrammer disposing…

Ear disposing:JavaProgrammer Ear

Eye disposing:JavaProgrammer Eye

SoftwareProgrammer disposing…

Ear disposing:SoftwareProgrammer Ear

Eye disposing:SoftwareProgrammer Eye

Farmer disposing…

Ear disposing:Farmer Ear

Eye disposing:Farmer Eye

People disposing…

Ear disposing:People Ear

Eye disposing:People Eye

结论:清理的顺序和初始化的顺序相反。从子类向基类逐渐清理。

GC中的引用计数法:每new一个对象的时候,计数器counter计算count对象的数量。此后清理的时候,会根据这个count值进行清理。

以后会专门写几篇关于GC的文章

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107767.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • jmeter聚合报告和汇总报告有什么区别_jmeter报告分析

    jmeter聚合报告和汇总报告有什么区别_jmeter报告分析Jmeter的聚合报告参数详解:#在执行前,需要设置好一个csv空文件,将执行结果刷到该文件中,方便演示各参数实例计算值,导出的报告示例如下#Label:就是请求名称#Samples:总线程数,值=线程数*循环次数Average:单个请求的平均响应时间,值=总运行时间/发送到服务器的总请求数,截图中的值是这么计算出来的>login:(6+15)/2=…

    2025年8月13日
    5
  • 因特网是一种什么网_广域网是因特网吗

    因特网是一种什么网_广域网是因特网吗以太网详解(一)

    2022年10月18日
    3
  • RealVNC Server Ubuntu 20.04 无显示器连接 虚拟显示器

    RealVNC Server Ubuntu 20.04 无显示器连接 虚拟显示器以前尝试过完全不接显示器,vnc连接设置总是不成功,这次很容易做成功了,记录一下。以前记录的远程桌面使用心得:https://blog.csdn.net/u012911347/article/details/80475254RealVNC远程连接带显示器模式:https://blog.csdn.net/u012911347/article/details/81209222RealVNC远程连接无显示器模式,但是要用非原生桌面:https://blog.csdn.net/u012911

    2022年8月21日
    34
  • 傅里叶、拉普拉斯、z变换常用公式合集「建议收藏」

    傅里叶、拉普拉斯、z变换常用公式合集「建议收藏」傅里叶变换常用信号的傅里叶变换傅里叶变换的性质傅里叶性质—典型变换对拉普拉斯常用信号的单边拉普拉斯变换拉普拉斯变换的性质z变换常用序列的z变换z变换的性质…

    2022年7月17日
    24
  • ROC曲线及AUC值[通俗易懂]

    ROC曲线及AUC值[通俗易懂]ROC曲线参考文献:【ROC曲线与AUC值】1.介绍及引入ROC的全名叫做ReceiverOperatingCharacteristic,其主要分析工具是一个画在二维平面上的曲线——ROCcurve。平面的横坐标是falsepositiverate(FPR),即假阳性率(1−Sp1-Sp1−Sp);纵坐标是truepositiverate(TPR),即真阳性率(SnSnSn)。对某个分类器而言,我们可以根据其在测试样本上的表现得到一个TPR和FPR点对。这样,此分类器就可以映射成

    2022年5月16日
    61
  • **解决mysql 1045拒绝登陆的问题**

    **解决mysql 1045拒绝登陆的问题**解决mysql1045拒绝登陆的问题当你登录MySQL数据库出现:Error1045错误时(如下图),就表明你输入的用户名或密码错误被拒绝访问了,最简单的解决方法就是将MySQL数据库卸载然后重装,但这样的缺点就是就以前的数据库中的信息将丢失,如果你不想重装,那么就需要找回密码或者重置密码。解决的方法应该有多种,这里我推荐大家使用一种原理通过,操作简单的方法,适用于windows以及linux平

    2022年5月2日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号