java学习笔记 2022.2.11

2022.2.11

on java 8 摘录(反射)

  1. 加载。这是由类加载器执行的。该步骤会先找到字节码(通常在类路径中的磁盘上,但也不一定),然后从这些字节码中创建一个Class对象。
  2. 链接。链接阶段会验证类中的字节码,为静态字段分配存储空间,并在必要时解析该类对其他类的所有引用。
  3. 初始化。如果有基类的话,会先初始化基类,执行静态初始化器和静态初始化块。
  1. 初始化被延迟到首次引用静态方法(构造器是隐式静态的)或非常量静态字段时:

    // reflection/ClassInitialization.java
    import java.util.*;
    
    class Initable {
      static final int STATIC_FINAL = 47;
      static final int STATIC_FINAL2 =
        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");
        // 不会触发初始化
        System.out.println(Initable.STATIC_FINAL);
        // 触发初始化
        System.out.println(Initable.STATIC_FINAL2);
        // 触发初始化
        System.out.println(Initable2.staticNonFinal);
        Class initable3 = Class.forName("Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
      }
    }
    /* 输出:
    After creating Initable ref
    47
    Initializing Initable
    258
    Initializing Initable2
    147
    Initializing Initable3
    After creating Initable3 ref
    74
    */
    

    实际上,初始化会“尽可能懒惰”。从initable引用的创建过程中可以看出,仅使用.class语法来获取对类的引用不会导致初始化。而Class.forName()会立即初始化类以产生Class引用,如initable3的创建所示。

    如果一个static final字段的值是“编译时常量”,比如Initable.staticFinal,那么这个值不需要初始化Initable类就能读取。但是把一个字段设置为staticfinal并不能保证这种行为:对Initable.staticFinal2的访问会强制执行类的初始化,因为它不是编译时常量。

    如果static字段不是final的,那么访问它时,如果想要正常读取,总是需要先进行链接(为字段分配存储)和初始化(初始化该存储),正如在对Initable2.staticNonFinal的访问中看到的那样。

一个Class引用表示的就是它所指向的确切类型:Class类的一个对象。

要想放松使用泛化的Class引用时的限制,请使用通配符?,它是Java泛型的一部分,表示“任何事物”。

尽管如我们看到的那样,普通的Class并不会产生编译器警告,但是和普通的Class相比,我们还是倾向于Class<?>,即使它们是等价的。Class<?>的好处在于,它表明了你不是偶然或无意识地使用了非具体的类引用。你就是选择了这个非具体的版本。

这种写法的话如果想表示子类可以这样<? extend 父类>

package reflection.toys;

public class GenericToyTest {
    public static void
    main(String[] args) throws Exception {
        Class<FancyToy> ftc = FancyToy.class;
        // 生成确切的类型:
        FancyToy fancyToy =
                ftc.getConstructor().newInstance();
        Class<? super FancyToy> up = ftc.getSuperclass();
        // 下面的代码无法通过编译:
        // Class<Toy> up2 = ftc.getSuperclass();
        // 只能生成Object
        Object obj = up.getConstructor().newInstance();
    }
}

这段代码很有意思,如果去掉第六行括号内的内容,会导致ftc得到的是一个Object类型,

问题

19.2 Class

  1. 首先Class类的作用就是描述了一个类的Class类文件中的信息,包括它的初始化器,它的接口,它的静态变量,它的父类这些信息

  2. Class类的每一个类的实例都是唯一确定,例如一个类叫做Cat,那么我在实例化Cat以后,它的Class对象也就生成了,同时,此时我们初始化变量

    Cat one = new Cat();
    Class cat = Cat.class;
    Cat two = new Cat();
    Class cat1 = Cat.class;
    

    应该理解成这两个引用是相同的,不管我后面会不会再去实例化Cat一个新的对象

  3. 从上面可以推导出,Class类实际上是让我们有了直接操作类的实例化的可能性,因为不使用Class类时,这些都是java帮我们解决的

  4. 还要注意Class类的加载是在编译阶段的,而Class类的实例化是在运行时的,而前缀为static final就是编译时常量,如果去掉final,那么静态常量就是可以修改的,所以去掉以后算运行时常量,而运行的化会导致Class对象被初始化,

  5. 如何利用Class类生成实例对象

    class cat {
        private String name="hajdka";
        private int age=131;
        public cat(){
    
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    public class GenericClassReferences {
        public static void main(String[] args) {
            try{
                System.out.println(cat.class.getConstructor().newInstance().getAge()+" "+cat.class.getConstructor().newInstance().getName());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    

其他

  1. default :包访问权限,即同一个包中的类可以可见。默认不显式指定访问控制权限时就是 default 包访问控制权限。

  2. 初始化(英語:Initialization)在计算机编程领域中指为数据对象变量赋初值的做法,如何初始化则取决于所用的程序语言以及所要初始化的对象的存储类型等属性。用于进行初始化的程序结构则称为初始化器或初始化列表。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cjz-lxg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值