zoukankan      html  css  js  c++  java
  • 类型信息(编程思想)

    类型信息
    class Candy {
    static { System.out.println("Loading Candy"); }
    }

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

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

    public class SweetShop {
    public static void main(String[] args) {
    System.out.println("inside main");
    new Candy();
    System.out.println("After creating Candy");
    try{
    Class.forName("Gum");
    }catch(Exception ex){
    System.out.println("Couldn't find Gum");
    }
    System.out.println("After Class.forName("Gum")");
    new Cookie();
    System.out.println("After creating Cookie");
    }
    /**
    * 每个类中的static块在第一次加载时执行
    * Class对象仅在需要的时候被加载,static初始化是在类加载时进行的
    * Class.forName()得到class对象的引用,如果该类没有进行加载,那就加载它。终于知道加载jdbc连接驱动的时候真正想要执行的是static块。Class.forName("com.jdbc.mySql.Driver")
    */
    }

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

    class Toy {
    Toy() {}
    Toy(int i) {}
    }
    class FancyToy extends Toy implements HasBatteries, Waterproof, Shoots {
    FancyToy() { super(1); }
    }
    public 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());
    }
    public static void main(String[] args) {
    Class c = null;
    try{
    c = Class.forName("com.zhen.type_information.FancyToy");
    }catch(ClassNotFoundException e) {
    System.out.println("Can't find FancyToy");
    System.exit(1);
    }
    printInfo(c);
    for(Class face : c.getInterfaces()){
    printInfo(face);
    }
    Class up = c.getSuperclass();
    Object obj = null;
    try{
    //Requires default constructor
    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);
    }
    printInfo(obj.getClass());
    }
    }
    Class.forName()中的字符串中,必须使用全限定定名(包含包名)
    getSimpleName()和getCnnonicalName()来产生不含包名的类名和全限定的类名
    isInterface()
    Class.getInstance()返回的是Class对应对象
    getSuperclass()查询直接基类
    类字面常量
    java还提供了另一种方法来生成对Class对象的引用,即使用类字面常量。类似这样:
    FancyToy.class
    这样做不仅更简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try语句块中)。并且它根除了对forName()方法的调用,所以也更高效。
    例如:
    boolean.class 等价于Boolean.TYPE
    void.class 等价于Void.TYPE
    建议使用".class",以保证与普通类的一致性。
    注意,当使用“.class”来创建对Class对象的引用时,不会自动地初始化该Class对象。为了使用类而做的准备工作实际包含三个步骤:
    1、加载,这是由类加载器执行。该步骤将查找字节码,并从这些字节码中创建一个Class对象
    2、链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,而且如果必须的话,将解析这个类创建的对其他类的所有引用
    3、初始化。如果该类具有超类,将对其初始化,执行静态初始化器和静态初始化块
    初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行
    class Initable{
    static final int staticFinal = 47;
    static final int staticFinal2 = ClassInitialization.rand.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");
    }
    }
    public class ClassInitialization {
    public static Random rand = new Random(47);
    public static void main(String[] args) throws Exception{
    Class initable = Initable.class;
    System.out.println("After creating Initable ref");
    //Does not trigger initialization
    System.out.println(Initable.staticFinal);
    //Does trigger initialization
    System.out.println(Initable.staticFinal2);
    //Does trigger initialization
    System.out.println(Initable2.staticNonFinal);
    Class initable3 = Class.forName("com.zhen.type_information.Initable3");
    System.out.println("After creating Initable3 ref");
    System.out.println(Initable3.staticNonFinal);
    }
    }
    可以看出,使用方法.class语法来获得对类的引用不会引发初始化。但是为了产生Class引用,Class.forName()就立即进行了初始化。
    如果一个static final的值是“编译期常量”,就像Initable.staticFinal那样,那么这个值不需要对Initable类进行初始化就可以读取
    泛化的Class引用
    public class GenericClassReferences {
    public static void main(String[] args) {
    Class intClass = int.class;
    Class<Integer> genericIntClass = int.class;
    genericIntClass = Integer.class; //Same thing
    intClass = double.class;
    // genericIntClass = double.class; Illegal

    }
    }
    普通的类引用不会产生警告信息,你可以看到,尽管泛型类引用只能赋值为指向其声明的类型,但是普通的类引用可以被重新赋值为指向任何其他的Class对象。通过泛型语法,可以让编译器强制执行额外的类型检查。
    如果你希望稍微放松一些这种限制,应该怎么办呢?咋一看,好像你应该能够执行类似下面的操作:
    Class<Number> genericNumberClass = int.class;
    看起来似乎是起作用的,因为Integer继承自Number。但是它无法工作,因为Integer Class对象不是Number对象的子类。
    为了在使用泛化的Class引用时放松限制,我们使用了通配符,它是Java泛型中的一部分。通配符就是“?”,表示“任何事物”。
    public class WildcardClassReferences {
    public static void main(String[] args) {
    Class<?> intClass = int.class;
    intClass = double.class;
    }
    }
    在JavaSE5中,Class<?>优于平凡的class,即使他们是等价的,并且平凡的Class如你所见,不会产生编译警告信息。Class<?>的好处是它表示你并非是由于碰巧或者是由于疏忽,而使用了一个非具体的类引用,你就是选择了非具体的版本。
    为了创建一个Class引用,它被限定为某种类型,或者改类型的任何子类型,你需要将通配符与extends关键字相结合,创建一个范围。
    public class BoundedClassReferences {
    public static void main(String[] args) {
    Class<? extends Number> bounded = int.class;
    bounded = double.class;
    bounded = Number.class;
    //Or anyting else derived from Number
    // bounded = String.class; Illegal
    }
    }
    class CountedInteger {
    private static long counter;
    private final long id = counter++;
    public String toString() { return Long.toString(id); }
    }
    public 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>();
    try{
    for(int i = 0; i < nElements; i++){
    result.add(type.newInstance());
    }
    } catch(Exception e) {
    throw new RuntimeException(e);
    }
    return result;
    }
    public static void main(String[] args) {
    FilledList<CountedInteger> fl = new FilledList<CountedInteger>(CountedInteger.class);
    System.out.println(fl.create(15));
    }
    }
    public class GenericToyTest {
    public static void main(String[] args) throws Exception {
    Class<FancyToy> ftClass = FancyToy.class;
    //Produces exact type
    FancyToy fancyToy = ftClass.newInstance();
    Class<? super FancyToy> up = ftClass.getSuperclass();
    // Class<Toy> up2 = ftClass.getSuperclass(); this won't compile
    Object obj = up.newInstance();
    }
    }
    如果你手头的是超类,那编译器将只允许你声明超类引用是“某个类”,它是FancToy超类,就像在表达式Class<? Super FancyToy>中所看到的,而不会接受Class<Toy>这样的声明。这看起来显得有些怪,因为getSuperClass()方法返回的是基类(不是接口),并且编译器在编译期就知道它是什么类型了——在本类中就是Toy.class——而不仅仅只是“某个类,它是FancyToy超类”。不管这样,正是由于这种含糊性,up.newInstance()返回的不是精确类型,而只是Object。

    新的类型转换
    java SE5还添加了用于Class引用的转型语法,即cast()方法 ,说实话,这让我想起异常ClassCastException
    class Building {}
    class House extends Building {}
    public class ClassCasts {
    public static void main(String[] args) {
    Building b = new House();
    Class<House> houseType = House.class;
    House h = houseType.cast(b);
    h = (House)b; //... or just do this
    }
    }
    类型转换前先做检查
    传统的类型转换,执行错误报错ClassCastException
    通过查询Class对象可以获取运行时所需的信息
    java中第三种形式,关键字instanceof。返回布尔值,告诉我们对象是不是某个特定类型的实现
    动态的instanceof
    Class对象的isInstance()方法
    反射:运行时的类信息
    Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包括了Field、Method以及Constructor类
    类方法提取器:
    public class ShowMethods {
    public 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) {
    args = new String[]{"com.zhen.type_information.t1.ClassCasts"};
    if(args.length < 1) {
    System.out.println(usage);
    System.exit(0);
    }
    int lines = 0;
    try{
    Class<?> c = Class.forName(args[0]);
    Method[] methods = c.getMethods();
    Constructor[] ctors = c.getConstructors();
    if(args.length == 1){
    for(Method method : methods) {
    System.out.println(p.matcher(method.toString()).replaceAll(""));
    }
    for(Constructor ctor : ctors){
    System.out.println(p.matcher(ctor.toString()).replaceAll(""));
    }
    lines = methods.length + ctors.length;
    } else {
    for(Method method : methods){
    if(method.toString().indexOf(args[1]) != -1) {
    System.out.println(p.matcher(method.toString()).replaceAll(""));
    }
    lines ++;
    }
    for(Constructor ctor : ctors){
    if(ctor.toString().indexOf(args[1]) != -1){
    System.out.println(p.matcher(ctor.toString()).replaceAll(""));
    }
    lines++;
    }
    }
    }catch (ClassNotFoundException e){
    System.out.println("No such class: " + e);
    }
    }
    }
    动态代理
    class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;
    public DynamicProxyHandler(Object proxied) {
    this.proxied = proxied;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("**** proxy: " + proxy.getClass() + ".method: " + method + ", args: " + args);
    if(args != null){
    for(Object arg: args){
    System.out.println(" " + arg);
    }
    }
    return method.invoke(proxied, args);
    }
    }
    public class SimpleDynamicProxy {
    public static void consumer(Interface iface) {
    iface.doSomething();
    iface.somethingElse("bonobo");
    }
    public static void main(String[] args) {
    RealObject real = new RealObject();
    consumer(real);
    //Insert a proxy and call again
    Interface proxy = (Interface) Proxy.newProxyInstance(
    Interface.class.getClassLoader(),
    new Class[]{ Interface.class},
    new DynamicProxyHandler(real)
    );
    consumer(proxy);
    }
    }
    Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器,一个你希望该代理实现的接口列表(不是类或抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求转发。

    空对象Null
    每次引用都测试是否为null,太恶心了。有时候引入空对象的思想会很有用

  • 相关阅读:
    627. Swap Salary
    176. Second Highest Salary
    596. Classes More Than 5 Students
    183. Customers Who Never Order
    181. Employees Earning More Than Their Managers
    182. Duplicate Emails
    175. Combine Two Tables
    620. Not Boring Movies
    595. Big Countries
    HDU 6034 Balala Power! (贪心+坑题)
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/7459429.html
Copyright © 2011-2022 走看看