资讯专栏INFORMATION COLUMN

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

tomorrowwu / 903人阅读

摘要:通过运行时类型信息,程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。编程应该尽量面向接口编程,应该对类型信息尽量的少了解二对象看书,书上写得好静态语句块在这个类被加载的时候运行。

一、为什么需要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 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 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 genericIntClass=int.class;

这是错的

Class 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 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 {
    private Class type;
    public FilledList(Class type) {
        this.type = type;
    }
    public List create(int nElements) {
        List result = new ArrayList();
        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类”
这两个是有区别的

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> 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 create();
}
class Filter extends Part {}
class FuelFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory {
        public FuelFilter create() {
            return new FuelFilter();
        }
    }
}
class AirFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory {
        public AirFilter create() {
            return new AirFilter();
        }
    }
}
class CabinAirFilter extends Filter {
    public static class Factory
            implements
                tij.classinfomation.Factory {
        public CabinAirFilter create() {
            return new CabinAirFilter();
        }
    }
}

class Belt extends Part {}

class FanBelt extends Belt {
    public static class Factory
            implements
                tij.classinfomation.Factory {
        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:
"
            + "ShowMethods qualified.class.name
"
            + "To show all methods in class or:
"
            + "ShowMethods qualified.class.name word
"
            + "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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67589.html

相关文章

  • Thinking in Java11 持有对象

    摘要:迭代器解决了这个问题。删除后于是我们可以写一个方法,接受一个类型,然后让他调用方法,这就不需要考虑这个是个还是了,也就是说,可以将遍历容器的操作与序列底层的结构分离,迭代器统一了对容器类的访问方式。十二和两种遍历的方法,与迭代器方法。 一、泛型和类型安全的容器 package tij.hoding; import java.util.ArrayList; public class ...

    v1 评论0 收藏0
  • Thinking in Java13 字符串

    摘要:四上的操作看五格式化输出运用和语言很相似和是等价的哟类格式化说明符转换六正则表达式网上教程学七扫描输入新增了类。 一、不可变String String类型的对象是不可变的,所有的改变实际上都是创建了一个新的String对象,另外当String作为传入参数的时候,其实实际上传入的是这个引用的一个拷贝,这个方法结束了之后这个传入的引用也就消失了,原来的那个String不会受到方法内的影响而...

    feng409 评论0 收藏0
  • Thinking in Java20 注解

    摘要:而这可以通过注解办到,在代码中以指令语言的形式化方法来为代码提供更多信息。有注解的说明这个成员变量是一个列名,然后根据注解信息来生成相应的语句。也就是说把注解信息提取了出来。 注解是向代码中添加信息的一种方法,并且在之后还可以使用这些数据就比如这个方法是用来剥香蕉的,但是我们看就是一串代码,我们没办法在代码里写一段指令说我这个程序是用来剥香蕉的,当然除了注释。而这可以通过注解办到,在代...

    刘玉平 评论0 收藏0
  • Thinking in Java12 通过异常处理错误

    摘要:异常处理程序抛出的异常必须在异常处理程序中得到处理。终止与恢复异常处理有两种模型,支持终止模型,一旦异常被抛出,表明错误无法挽回,无法退回来继续执行之前出错的代码。对于异常来说,最重要的部分就是类名。 一、概念 使用异常能降低处理错误代码的复杂程度,并且将错误在一个地方进行处理,于是将描述在正常行为过程中做过什么事的代码和出了问题怎么办的代码相分离 二、基本异常 异常情形指的是当前环境...

    miguel.jiang 评论0 收藏0
  • Thinking in Java9 接口

    摘要:但如果导出类还有抽象方法,那这个类还应该加上声明为抽象类。并且接口具有继承的一系列特点,如向上转型等等。接口中的方法是自动是的。 Thinking in Java 好书全是干货 一、抽象类和抽象方法 抽象方法:这种方法只有声明而没有方法体,下面是抽象方法生命所采用的语法 abstract void f(); 包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,该类必须被限定为...

    CoorChice 评论0 收藏0

发表评论

0条评论

tomorrowwu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<