索鸟网

  1. 首页
  2. (Thinking in Java)第14章 类型信息

(Thinking in Java)第14章 类型信息


一、为什么需要RTTI

Run-Time Type Information。通过运行时类型信息,程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
编程应该尽量面向接口编程,应该对类型信息尽量的少了解

package tij.classinfomation;

import java.util.Arrays;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Shape> shapeList = Arrays.asList(new Circle(), new Square(),
                new Triangle());
        for (Shape shape : shapeList) {
            shape.draw();
        }
    }

}
abstract class Shape {
    void draw() {
        System.out.println(this + ".draw");
    }
    abstract public String toString();
}
class Circle extends Shape {
    public String toString() {
        return "Circle";
    }
}
class Square extends Shape {
    public String toString() {
        return "Square";
    }
}
class Triangle extends Shape {
    public String toString() {
        return "Triangle";
    }
}

二、Class对象

看书,书上写得好

package tij.classinfomation;

public class Test {

    public static void main(String[] args) {
        System.out.println("inside main");
        new Candy();
        System.out.println("After creating Candy");
        try {
            Class<Gum> clazz = Gum.class;
            String class_name = clazz.getName();
            System.out.println(class_name);
            Class.forName(class_name);
        } catch (ClassNotFoundException e) {
            System.out.println("Couldn't find Gum");
        }
        System.out.println("After Class.forname(\"Gum\")");
        new Cookie();
        System.out.println("After creating Cookies");
    }

}

class Candy {
    static {
        System.out.println("Loading Candy");
    }
}
class Gum {
    static {
        System.out.println("Loading Gum");
    }
}
class Cookie {
    static {
        System.out.println("Loading Cookie");
    }
}

静态语句块在这个类被加载的时候运行。
其中Class.forName方法中要写类的绝对路径,包名+类名,同时调用Gum.class.getName的时候,也并没有加载Gum类。
另外

class tt{
    static void showt(){
        System.out.println("showt");
    }
    static{
        System.out.println("ttstatic");
    }
}
class jj extends tt{
    static void showj(){
        System.out.println("showj");
    }
    static{
        System.out.println("jjstatic");
    }
}
public class Test {
    public static void main(String[] args) {
        jj.showt();
    }
}

虽然调用的事jj.showt,但是并没有加载jj这个类,而是加载了tt这个类。
所以就验证了,运行时是实际用谁了,才加载谁

package tij.classinfomation;

public class Test {
    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("tij.classinfomation.FancyToy");
        } catch (ClassNotFoundException e) {
            System.out.println("Can't find FancyToy");
            System.exit(1);
        }
        ToyTest.printInfo(c);
        System.out.println("-----------------");
        for (Class face : c.getInterfaces()) {
            ToyTest.printInfo(face);
        }
        System.out.println("-----------------");
        Class up = c.getSuperclass();
        Object obj = null;
        try {
            obj = up.newInstance();
        } catch (InstantiationException e) {
            System.out.println("Cannot instantiate");
            System.exit(1);
        } catch (IllegalAccessException e) {
            System.out.println("Cannot access");
            System.exit(1);
        }
        ToyTest.printInfo(obj.getClass());
    }

}

interface HasBatteries {}
interface Waterproof {}
interface Shoots {}

class Toy {
    Toy() {}
    Toy(int i) {}
}
class FancyToy extends Toy implements HasBatteries, Waterproof, Shoots {
    FancyToy() {
        super(1);
    }
}
class ToyTest {
    static void printInfo(Class cc) {
        System.out.println("Class name:" + cc.getName() + " is interface?["
                + cc.isInterface() + "]");
        System.out.println("Simple name:" + cc.getSimpleName());
        System.out.println("Canonical name:" + cc.getCanonicalName());
    }
}

看书

1.类字面常量

类字面常量就是

FancyToy.class;

基本类型也可以用的,这个方法不会自动初始化这个类对象

要使用类的话,要进行三个步骤

package tij.classinfomation;

import java.util.Random;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class initable = Initable.class;
        System.out.println("After Initable ref");
        System.out.println(Initable.staticFinal);
        System.out.println(Initable.staticFinal2);

        System.out.println(Initable2.staticNonFinal);
        Class initable3 = Class.forName("tij.classinfomation.Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
    }

}

class Initable {
    static final int staticFinal = 47;
    static final int staticFinal2 = new Random(47).nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}
class Initable2 {
    static int staticNonFinal = 147;
    static {
        System.out.println("Initializing Initable2");
    }
}
class Initable3 {
    static int staticNonFinal = 74;
    static {
        System.out.println("Initializing Initable3");
    }
}

2.泛化的Class引用

Class<Number> genericIntClass=int.class;

这是错的

Class<? extends Number> genericIntClass = Integer.class;

这个可以

Class<?> genericIntClass = Integer.class;

有个<?>比class光杆优雅

package tij.classinfomation;

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        FilledList<CountedInteger> fl = new FilledList<>(CountedInteger.class);
        System.out.println(fl.create(15));
    }

}
class CountedInteger {
    private static long counter;
    private final long id = counter++;
    public String toString() {
        return Long.toString(this.id);
    }
}
class FilledList<T> {
    private Class<T> type;
    public FilledList(Class<T> type) {
        this.type = type;
    }
    public List<T> create(int nElements) {
        List<T> result = new ArrayList<T>();
        for (int i = 0; i < nElements; i++) {
            try {
                result.add(type.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

B.class.getSuperclass()指的是“某各类,且是B的父类”
Class<A>指的是“A类”
这两个是有区别的

3.新的转型语法

没啥卵用= =就是类型装换嘛

三、类型转换前先做检查

看书吧= =这段太费劲了。

四、注册工厂

要在已有的继承关系中添加新的继承关系,最合适的就是应该将新添加的类再父类中完成注册。
结合工厂设计模式

package tij.classinfomation;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println(Part.createRandom());
        }
    }

}

class Part {
    public String toString() {
        return this.getClass().toString();
    }
    static List<Factory<? extends Part>> partFactories = new ArrayList<>();
    static {
        partFactories.add(new FuelFilter.Factory());
        partFactories.add(new AirFilter.Factory());
        partFactories.add(new CabinAirFilter.Factory());
        partFactories.add(new FanBelt.Factory());
    }
    private static Random rand = new Random(47);
    static Part createRandom() {
        int n = rand.nextInt(partFactories.size());
        return partFactories.get(n).create();
    }
}

interface Factory<T> {
    T create();
}
class Filter extends Part {}
class FuelFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory<FuelFilter> {
        public FuelFilter create() {
            return new FuelFilter();
        }
    }
}
class AirFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory<AirFilter> {
        public AirFilter create() {
            return new AirFilter();
        }
    }
}
class CabinAirFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory<CabinAirFilter> {
        public CabinAirFilter create() {
            return new CabinAirFilter();
        }
    }
}

class Belt extends Part {}

class FanBelt extends Belt {
    public static class Factory
            implements
                tij.classinfomation.Factory<FanBelt> {
        public FanBelt create() {
            return new FanBelt();
        }
    }
}

任何新添加的子类,只要在part类中新添加一个add就可以完成注册了。
另外此处运用到了工厂方法,往列表里添加的也是一个工厂对象,这样的意义在于将创建对象的任务交给各个对象自己的工厂来办,利用多态的性质,在新添加的类中相似实现工厂可以达到生成新的子类的对象的目的。

五、instanceof与Class的等价性

package tij.classinfomation;

public class Test {
    public static void main(String[] args) {
        FamilyVsExactType.test(new Derived());
        FamilyVsExactType.test(new Base());
    }

}

class Base {}
class Derived extends Base {}
class FamilyVsExactType {
    static void test(Object x) {
        print("Tseting x of type " + x.getClass());
        print("x instanceof Base " + (x instanceof Base));
        print("x instanceof Derived " + (x instanceof Derived));
        print("Base.isInstance(x) " + (Base.class.isInstance(x)));
        print("Derived.isInstance(s) " + Derived.class.isInstance(x));
        print("x.getClass()==Base.class " + (x.getClass() == Base.class));
        print("x.getClass().equals(Base.class) "
                + (x.getClass().equals(Base.class)));
        print("x.getClass()==Derived.class " + (x.getClass() == Derived.class));
        print("x.getClass().equals(Derived.class) "
                + (x.getClass().equals(Derived.class)));
    }
    static void print(String s) {
        System.out.println(s);
    }
}

六、反射:运行时的类信息

package tij.classinfomation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.regex.Pattern;

public class Test {
    private static String usage = "usage:\n"
            + "ShowMethods qualified.class.name\n"
            + "To show all methods in class or:\n"
            + "ShowMethods qualified.class.name word\n"
            + "To search for methods involving 'word'";
    private static Pattern p = Pattern.compile("\\w+\\.");
    public static void main(String[] args) {
        Class<?> c = Test.class;
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            System.out.println(p.matcher(method.toString()).replaceAll(""));
        }
        Constructor[] ctors = c.getConstructors();
        for (Constructor constructor : ctors) {
            System.out
                    .println(p.matcher(constructor.toString()).replaceAll(""));
        }
    }

}

七、动态代理

package tij.classinfomation;

public class Test {
    public static void main(String[] args) {
        Interface Aface = new RealObject();
        Aface.doSomething();
        Aface.somethingElse("bonobo");
        System.out.println("------------");
        Interface Bface = new SimpleProxy(Aface);
        Bface.doSomething();
        Bface.somethingElse("bonobo");
    }
}

interface Interface {
    void doSomething();
    void somethingElse(String arg);
}

class RealObject implements Interface {
    public void doSomething() {
        System.out.println("doSomething");
    }

    public void somethingElse(String arg) {
        System.out.println("somethingElse " + arg);
    }
}

class SimpleProxy implements Interface {
    private Interface proxied;
    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }
    public void doSomething() {
        System.out.println("SimpleProxy doSomething");
        proxied.doSomething();
    }

    public void somethingElse(String arg) {
        System.out.println("SimpleProxy somethingElse " + arg);
        proxied.somethingElse(arg);
    }
}

我觉得这块讲的不是很好,CZ那边这里讲的就很好。

八、空对象

没懂= =

end

java

来源地址:https://segmentfault.com/a/1190000010653763 版权归作者所有!

相关教程

  • 第14章 类型信息---读书笔记

    基础知识 运行时候的类型信息,使得你在程序运行时发现和使用类型信息 RTTI: Run-Time Type Information java让我们在运行时候识别对象和类型信息的两种方式: 一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型 另外的一种是反射机制,它允许我们在运行时发现和使用类的信息 下面的代码很重要: //: typeinfo/Shapes.java imp
  • (Thinking in Java)第13章 字符串

    一、不可变String String类型的对象是不可变的,所有的改变实际上都是创建了一个新的String对象,另外当String作为传入参数的时候,其实实际上传入的是这个引用的一个拷贝,这个方法结束了之后这个传入的引用也就消失了,原来的那个String不会受到方法内的影响而改变。 package tij.string; public class Tes
  • (Thinking in Java)第20章 注解

    注解是向代码中添加信息的一种方法,并且在之后还可以使用这些数据就比如这个方法是用来剥香蕉的,但是我们看就是一串代码,我们没办法在代码里写一段指令说“我这个程序是用来剥香蕉的”,当然除了注释。而这可以通过注解办到,在代码中以Java指令语言的形式化方法来为代码提供更多信息。 一、基本语法 1.定义注解 package tij.annotation; im
  • (Thinking in Java)第9章 接口

    Thinking in Java 好书全是干货 一、抽象类和抽象方法 抽象方法:这种方法只有声明而没有方法体,下面是抽象方法生命所采用的语法 abstract void f(); 包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的,并且编译器不会允许直接创建一个抽象类对象,正确的做法是从这个抽象类继承并为抽象方法完成定义
  • (Thinking in Java)第11章 持有对象

    一、泛型和类型安全的容器 package tij.hoding; import java.util.ArrayList; public class Test { @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayLi
  • (Thinking in Java)第15章 泛型

    二、简单泛型 2.一个堆栈类 package tij.generic; public class Test { public static void main(String[] args) { LinkedStack<String> lss = new LinkedStack<String>();
  • (Thinking in Java)第10章 内部类

    Thinking in Java捞干货,写笔记 一、成员内部类 1.最基本使用 public class Demo { class Contents{ private int i=11; public int value(){ return i; } } c
  • (Thinking in Java)第12章 通过异常处理错误

    一、概念 使用异常能降低处理错误代码的复杂程度,并且将错误在一个地方进行处理,于是将“描述在正常行为过程中做过什么事”的代码和“出了问题怎么办”的代码相分离 二、基本异常 异常情形指的是当前环境下没有足够的信息来让我们解决这个问题,比如当除数为0发生的时候,我们不知道除数为零代表着什么,(比如在算淘宝购物花销所占百分比的时候,你发现你这个月根本没花钱,总