文章目录

  1. 1. 令人混淆的构造器
    1. 1.1. 分析
    2. 1.2. 建议
  2. 2. 狸猫变犬子
    1. 2.1. 分析
    2. 2.2. 建议
  3. 3. 我所得到的都是静态的
    1. 3.1. 分析
    2. 3.2. 修改
  4. 4. 不是你的类型
    1. 4.1. 分析
    2. 4.2. 问题:不是你的类型(续)
    3. 4.3. 分析
  5. 5. 特创论
    1. 5.1. 建议

摘自《Java解惑》。这些问题都很经典,可以细细品味。
今天讲解的问题如下,令人混淆的构造器、狸猫变犬子、我所得到的都是静态的、不是你的类型、不是你的类型(续)、特创论。

令人混淆的构造器

public class Confusing {  
  public Confusing(Object obj){  
      System.out.println("Object");  
  }  
  public Confusing(String str){  
      System.out.println("String");  
  }  
  public static void main(String[] args){  
      new Confusing(null);  
  }  
}

分析

Java的重载解析过程可以分为两个阶段。第一阶段,选取所有可获得并且可应用的方法或构造器。第二阶段,在第一阶段选择的方法或构造器中选取最精确的一个。

建议

想要强制要求编译器选择一个精确的重载版本,需要将实参转型为形参所声明的类型。重载版本的解析可能会产生混淆,应该尽可能避免重载。如果确定进行了重载 ,请保证所有的重载版本所接受的参数类型都是互不兼容的。

狸猫变犬子

class Counter{  
  private static int count;  
  public static void increment(){count++;}  
  public static int getCount(){return count;}  
}  
class Dog extends Counter{  
  public void woof(){increment();}  
}  
class Cat extends Counter{  
  public void meow(){increment();}  
}  
public class Ruckus {  
  public static void main(String[] args){  
      Dog dog = newDog();  
      dog.woof();  
      Catcat = newCat();  
      cat.meow();  
      System.out.println(dog.getCount()+"woof");  
      System.out.println(cat.getCount()+"meow");  
  }  
}

分析

静态字段由声明它的类及其子类所共享。

建议

如果需要让每一个子类都具有某个单独副本,那么必须在每一个子类中声明一个单独的静态字段。

我所得到的都是静态的

class Car{  
  public static void bark(){  
      System.out.println("Dodo");  
  }  
}  
class SubCar extends Car{  
  public static void bark(){}  
}  
public class Bark {  
  public static void main(String[] args){  
      Car car = newCar();  
      Car subcar = newSubCar();  
      car.bark();  
      subcar.bark();  
  }  
}

分析

静态方法是不能被覆写的,它们只能被隐藏。

修改

①类名.方法名:SubCar.bark();

②删掉static

不是你的类型

public class Type {  
  public static void main(String[] args){  
      String s = null;  
      System.out.println(sinstanceofString);  
  }  
}

分析

instanceof操作符被定义为在做操作数为null时返回false。

问题:不是你的类型(续)

public class Type2 {  
  public static void main(String[] args){  
      System.out.println(newType() instanceof String);  
  }  
}

分析

错误。如果两个操作数的类型都是类,其中一个必须是另一个的子类型。

特创论

public class Creator {  
  public static void main(String[] args){  
      for(int i = 0; i < 100; i++) {  
          Creature creature = newCreature();  
      }  
      System.out.println(Creature.getNum());  
  }  
}  
class Creature{  
  privatestatic long num = 0;  
  publicCreature(){  
      num++;  
  }  
  publicstatic long getNum(){  
      return num;  
  }  
}

建议

①在使用一个变量来对实例的创建进行计数时,要使用long类型而不是int类型的变量,以防止溢出。

②要注意,如果多线程可以并行创建对象,那么递增计数器的代码和读取计数器的代码都应该被同步。可以利用synchronized。如果你使用的是5.0或更新的版本,你可以使用一个AtomicLong实例,它可以在面临并发时绕过对同步的需要。允许那些处理基于数字类的工具和实用工具进行统一访问。

(完)

微信公众号

文章目录

  1. 1. 令人混淆的构造器
    1. 1.1. 分析
    2. 1.2. 建议
  2. 2. 狸猫变犬子
    1. 2.1. 分析
    2. 2.2. 建议
  3. 3. 我所得到的都是静态的
    1. 3.1. 分析
    2. 3.2. 修改
  4. 4. 不是你的类型
    1. 4.1. 分析
    2. 4.2. 问题:不是你的类型(续)
    3. 4.3. 分析
  5. 5. 特创论
    1. 5.1. 建议