《JAVA编程思想》学习备忘(第277页Polymorphism-2)

续《JAVA编程思想》学习备忘(第277页Polymorphism-1)

Pitfall:"overriding" private methods

以下这个例子是重写了私有的方法吗?

public class PrivateOverride {
 private void f(){
  System.out.println("private f()");
 }
 public static void main(String[] args){
  PrivateOverride po = new Derived();
  po.f();
 }
}

public class Derived extends PrivateOverride {
 public void f(){
  System.out.println("public f()");
 }
}

输出:

private f()

正如标题,它是一个“陷阱”。

The result of this is that only non-private methods may be overriden,but you should watch out for the appearance of overriding private methods,which generates no compiler warnings,but doesn't do what you might expect.To be clear,you should use a different name from a private base-class method in your derived class.

 

Pitfall:fields and static methods

only ordinary method calls can be polymorphic.

示例:

class Sub extends Super {
 public int field = 1;
 public int getField(){return field;}
 public int getSuperField(){return super.field;}
}

class Super {
 public int field = 0;
 public int getField(){return field;}
}

public class FieldAccess {
 public static void main(String[] args) {
  Super sup = new Sub();
  System.out.println("sup.field = " + sup.field + ", sup.getField() = "
    + sup.getField());
  Sub sub = new Sub();
  System.out.println("sub.field = " + sub.field + ", sub.getField() = "
    + sub.getField() + ", sub.getSuperField() = "
    + sub.getSuperField());
 }
}

输出:

sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
When a Sub object is upcast to a Super reference,any field accesses are resolved by the compiler,and are thus not polymorphic.In this example,different storage is allocated for Supper.field and Sub.field.Thus,Sub actually contains two fields called field:its own and the one that it gets from Super.However,the Super version is not the default that is produced when you refer to field in Sub;in order to get the Super field you must explicitly say super.field.

If a method is static,it doesn't behave polymorphically:

public class StaticSuper {
 public static String staticGet(){
  return "Base staticGet()";
 }
 public String dynamicGet(){
  return "Base dynamicGet()";
 }
}

public class StaticSub extends StaticSuper {
 public static String staticGet(){
  return "Derived staticGet()";
 }
 public String dynamicGet(){
  return "Dervied dynamicGet()";
 }
}

public class StaticPolymorphism {
 public static void main(String[] args) {
  StaticSuper sup = new StaticSub();
  System.out.println(sup.staticGet());
  System.out.println(sup.dynamicGet());
 }
}

输出:

Base staticGet()
Dervied dynamicGet()
static methods are associated with the class,and not the individual objects.

 

Constructors and polymorphism

As usual,constructors are different from other kinds of methods.This is also true when polymorphism is involved.Even though constructors are not polymorphic(they're actually static methods,but the static declaration is implicit),it's important to understand the way constructors work in complex hierarchies and with polymorphism.This understanding will help you avoid unpleasant entanglements.

Order of constructor calls

A constructor for the base class is always called during the construction process for a derived class.

示例:

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

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

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

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

class Lunch extends Meal{
 Lunch(){System.out.println("Lunch()");}
}

class PortableLunch extends Lunch{
 PortableLunch(){System.out.println("PortableLunch()");}
}

public class Sandwich extends PortableLunch {
 private Bread b = new Bread();
 private Cheese c = new Cheese();
 private Lettuce l = new Lettuce();
 public Sandwich(){System.out.println("Sandwich()");}
 public static void main(String[] args) {
  new Sandwich();
 }
}

输出:

Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
试分析程序扫描轨迹:当实例化Sandwich时,先调用基类PortableLunch的构造方法,PortableLunch又先调用其基类Lunch的构造方法,lunch又先调用其基类Meal的构造方法,因此先输出Meal(),再输出Lunch(),再输出PortableLunch(),而后分别先声明并实例化私有成员属性Bread、Cheese、Lettuce,输出Bread()、Cheese()、Lettuce(),最后进入Sandwich构造方法输出:Sandwich()

 

Inheritance and cleanup

When using composition and inheritance to create anew class,most of the time you won't have to worry about cleaning up;subobjects can usually be left to the garbage collector.If you do have cleanup issues,you mustbe diligent and create a dispose() method(the name I have chose to use here;you may come up with something better)fro your new class.And with inheritance,you must override dispose() in the derived class if you have and special cleanup that must happen as part of garbage collection.When you override dispose() in an inherited class,it's important to remember to call the base-class version of dispose(),since otherwise the base-class cleanup will not happen.The following example demonstrates this:

class Characteristic {
 private String s;
 Characteristic(String s){
  this.s = s;
  System.out.println("Creating Characteristic " + s);
 }
 protected void dispose(){
  System.out.println("disposing Characteristic " + s);
 }
}

class Description{
 private String s;
 Description(String s){
  this.s = s;
  System.out.println("Creating Description " + s);
 }
 protected void dispose(){
  System.out.println("disposing Description " + s);
 }
}

class LivingCreature{
 private Characteristic p = new Characteristic("is alive");
 private Description t = new Description("Basic Living Creature");
 LivingCreature(){
  System.out.println("LivingCreature()");
 }
 protected void dispose(){
  System.out.println("LivingCreature dispose");
  t.dispose();
  p.dispose();
 }
}

class Animal extends LivingCreature{
 private Characteristic p = new Characteristic("has heart");
 private Description t = new Description("Animal not Vegetable");
 Animal(){
  System.out.println("Animal()");
 }
 protected void dispose(){
  System.out.println("Animal dispose");
  t.dispose();
  p.dispose();
  super.dispose();
 }
}

class Amphibian extends Animal{
 private Characteristic p = new Characteristic("can live in water");
 private Description t = new Description("Both water and land");
 Amphibian(){
  System.out.println("Amphibian()");
 }
 protected void dispose(){
  System.out.println("Amphibian dispose");
  t.dispose();
  p.dispose();
  super.dispose();
 }
}

public class Frog extends Amphibian {

 private Characteristic p = new Characteristic("Croaks");
 private Description t = new Description("Eats Bugs");
 public Frog(){
  System.out.println("Frog()");
 }
 protected void dispose(){
  System.out.println("Frog dispose");
  t.dispose();
  p.dispose();
  super.dispose();
 }
 public static void main(String[] args) {
  Frog frog = new Frog();
  System.out.println("Bye!");
  frog.dispose();
 }
}

输出:

Creating Characteristic is alive

Creating Description Basic Living Creature

LivingCreature()

Creating Characteristic has heart

Creating Description Animal not Vegetable

Animal()

Creating Characteristic can live in water

Creating Description Both water and land

Amphibian()

Creatin Characteristic Croaks

Creating Descripton Eats Bugs

Frog()

Bye!

Frog dispose
disposing Description Eats Bugs
disposing Characteristic Croaks
Amphibian dispose
disposing Description Both water and land
disposing Characteristic can live in water
Animal dispose
disposing Description Animal not Vegetable
disposing Characteristic has heart
LivingCreature dispose
disposing Description Basic Living Creature
disposing Characteristic is alive

需要注意:dispose()方法中,无论t.dispose()还是p.dispose(),都是本类中当前对象的调用(由于Frog对象控制其成员对象,所以未被“垃圾回收”),因此,方法中s字符串也为当前类中所传的内容。

示例:

class Shared {
 private int refcount = 0;
 private static long counter = 0;
 private final long id = counter++;
 public Shared(){
  System.out.println("Creating " + this);
 }
 public void addRef(){refcount++;}
 protected void dispose(){
  if(--refcount==0)
   System.out.println("Disposing " + this);
 }
 public String toString(){return "Shared " + id;}
}

class Composing{
 private Shared shared;
 private static long counter = 0;
 private final long id = counter++;
 public Composing(Shared shared){
  System.out.println("Creating " + this);
  this.shared = shared;
  this.shared.addRef();
 }
 protected void dispose(){
  System.out.println("disposing " + this);
  shared.dispose();
 }
 public String toString(){return "Composing " + id;}
}

public class ReferenceCounting {
 public static void main(String[] args) {
  Shared shared = new Shared();
  Composing[] composing = {
    new Composing(shared),
    new Composing(shared),
    new Composing(shared),
    new Composing(shared),
    new Composing(shared)
  };
  for(Composing c : composing)
   c.dispose();
 }
}

输出:

Creating Shared 0
Creating Composing 0
Creating Composing 1
Creating Composing 2
Creating Composing 3
Creating Composing 4
disposing Composing 0
disposing Composing 1
disposing Composing 2
disposing Composing 3
disposing Composing 4
Disposing Shared 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值