Java用个继承咋就这么难

试想一个问题:

如果我们需要给一个超类的方法实现一种更强的功能,也就是加强版的超类,一般会怎么做?

继承?

Too young too simple!

看看下面的例子:

当我们需要一个类,需要HashSet类的所有方法,但是随时需要知道在其创建到目前,已经加入过多少元素,该如何实现?

一般使用继承,覆盖add()和addAll()方法,会显得很合理:

 1 public class InstrumentedHashSet<E> extends HashSet<E>{
 2     private int mCount;
 3
 4     public int getmCount() {
 5         return mCount;
 6     }
 7     @Override
 8     public boolean add(E e) {
 9         mCount ++;
10         return super.add(e);
11     }
12     @Override
13     public boolean addAll(Collection<? extends E> e) {
14         mCount += e.size();
15         return super.addAll(e);
16     }
17 }

第9行和第14行进行了对mCount的增加,那么真的像我们想象的那样吗?

 1     public static void main(String[] args) {
 2         InstrumentedHashSet<String> mHashSet = new InstrumentedHashSet<String>();
 3
 4         ArrayList<String> mArrayList = new ArrayList<String>();
 5         mArrayList.add("1");
 6         mArrayList.add("2");
 7         mArrayList.add("3");
 8
 9         mHashSet.addAll(mArrayList);
10         System.out.println("总共插入了" + mHashSet.getmCount());
11
12     }

最后输出: 总共插入了9

Why?

其实是因为,在HashSet内部的实现中,addAll()方法是调用了add()方法的,这一点虽然坑爹,但是没有必要在文档中说明。在这个类中,只要我们去掉add()的覆盖,就可以良好的运行程序。

那么,问题来了,以后遇到这种需求的时候,还要不要用继承呢?

可能你认为这是个例,注意点就行了,那么,当你想要使用继承的时候,回答以下几个问题:

1.如果这样的父类在以后的版本中有改变呢?

2.如果父类加入了新的方法而自己却没有实现呢?

更甚至,你可能认为我使用继承,但是不覆盖原有方法就安全了?考虑以下几个问题:

1.如果超类添加了一个方法,而你给子类提供的方法的函数签名碰巧与它相同,但是返回结果不同。那么,编译器不会通过这个方法。

2.如果函数签名和返回类型都相同,那不又是继承了吗?

幸运的是,有一种办法可以解决以上问题,那就是看起来不起眼的 ——组合(复合)!

这样,原有的类就成了新类的一个组件,新类中的每个示例方法都可以调用被包含现有类示例中的对应方法,并返回它的结果,这被称为“转发”,新类中的方法被称为转发方法

这样的类非常稳固,即使向现有的类增加了新的方法,也不会影响新的类。

只有当子类是真正的超类的子类型的时候,才可以使用继承,也就是说,必须存在“is-a”关系时候才适合使用继承。

时间: 2024-10-09 23:37:05

Java用个继承咋就这么难的相关文章

JAVA中的继承

1.什么是继承 基于一个已存在的类,创建一个新的类.已存在的类即父类,新的类即子类,继承就是子类继承并拥有父类的属性和方法,同时,子类还有拥有父类所不具有的属性和方法. 父类,也称为基类.超类(superclass):子类,也称为派生类. 2.JAVA中"继承"的特点 JAVA中一个类只能继承一个父类.不像C++等语言那样,可以继承多个类.这也是JAVA比较容易学的一方面 只能继承父类中非private成员属性和方法,private是父类所特有的不能继承 3.JAVA中的"继

java中子类继承

[[email protected] java]# vim Ostrich.java //注意文件名必须是这个,因为下面代码中只有Ostrich是public修饰符.我们要明白public的含义 class Bird { public void Fly() { System.out.println("I am bird I can fly"); } } public class Ostrich extends Bird { public void Fly() { System.out.

Java中的继承、封装、多态的理解

Java中的继承.封装.多态 继承的理解: 1.继承是面向对象的三大特征之一,也是实现代码复用的重要手段.Java的继承具有单继承的特点,每个子类只有一个直接父类. 2.Java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类称为父类(有的也称其为基类.超类),父类和子类的关系,是一种一般和特殊的关系.就像是水果和苹果的关系,苹果继承了水果,苹果是水果的子类,水果是苹果的父类,则苹果是一种特殊的水果. 3.Java使用extends作为继承的关键字,extends关键字在

Java面向对象的继承

继承也是面向对象的又一重要特性,继承是类于类的一种关系,通俗来说狗属于动物类,那么狗这个类就继承了动物类 java中的继承是单继承的,一个类只能继承与一个父类 子类继承父类之后,子类就拥有了父类的所有属性和方法,private的除外,优点就是可以提高代码的复用性,简单的继承实例如下: 1 public class Dog extends Animal { 2 //Dog类继承了Animal类中的所有非私有的属性和方法,可以直接使用了 3 } 使用继承还是挺简单的 方法重写 如果子类对继承父类的方

黑马程序员——java基础--面向对象--继承

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 继承: 1.当一个类中包含了另一个类的所有变量个方法时,但另一个类中不包含另一个类的所有变量和方法时,表示范围比较小的就可以作为另一个的父类. 集合表示:A属于B,B不属于A,A就可以作为B的父类,B继承A 2.当只是为了获取其他类的功能的时候,不能为了简化代码而继承. 3.必须是类与类之间的所属关系才可以继承,所属关系看前面集合 继承的特点: 1.不支持多继承,只支持单继承: 多继承的话容易

Java面向对象之继承

Java 中的继承规则: 1.子类继承父类所有的成员变量和成员方法,但是不能继承父类的构造方法. 2.子类虽然继承了父类的成员变量,但是子类不能直接访问父类的私有变量,可以通过getter/setter()方法进行访问 3.子类对父类构造函数的调用规则: a.子类的构造方法首先必须调用父类的构造方法. b.如果没有显示指定,子类的构造方法会默认的调用父类中的无参构造方法, 1 public class Animal { 2 public Animal() { 3 System.out.print

浅谈Java中类的继承

继承作为面向对象的三大基本特征之一,也是Java中必不可少的组成部分.因此,Java中类的继承和其他面向对象语言的继承都是大同小异的. 继承的优点: 通过继承可以简化类的定义. Java只支持单继承,不允许多重继承. 可以有多承继承,即一个类可以继承某个类的子类,如类B继承了类A,类C又继承了类B,那么C也间接的继承了A. 子类继承所有父类的成员变量和成员方法,但不继承父类的构造方法.在子类的构造方法中,可使用语句super(参数列表)调用父类的构造方法. 如果子类的构造方法中没有显性的调用父类

再谈Java中类的继承

上篇博客谈到了Java中类的继承,但是那些远远不能满足我们在实际操作中的需要,那么怎么才能让子类的功能更强大,并且具有父类的属性呢? 一: 父类 1 public class A { 2 3 final String name="A"; 4 5 void A1(){}; 6 } 子类 1 public class AA extends A{ 2 3 String name="AA"; 4 5 void AA1(){}; 6 7 public static void

Java线程示例 - 继承Thread类和实现Runnable接口

进程(Process)和线程(Thread)是程序运行的两个基本单元.Java并发编程更多的是和线程相关. 进程 进程是一个独立的执行单元,可将其视为一个程序或应用.然而,一个程序内部同事还包含多个进程.Java运行时环境就是一个单独的进程,在它内部还包含了作为进程的各种类和程序. 线程 可以将线程看做轻量级的进程.线程存在于进程当中,需要的资源开销较小.同一进程中的线程共享进程的资源. Java多线程 每一个Java引用都只要有一个线程 - 主线程(main thread).虽然后台还运行着许