资讯专栏INFORMATION COLUMN

对象

nanfeiyan / 2170人阅读

摘要:入队列,即表示当前对象已回收。时,清空对象的属性即执行,再将对象加入该对象关联的中。当一个被掉之后,其相应的包装类对象会被放入中。原因是编译程序实现上的困难内部类对象的生命周期会超过局部变量的生命期。

一个类的静态成员在类的实例gc后,不会销毁。

对象引用强度

强引用Strong Reference

就是指在代码之中普遍存在的,类似:“Object objectRef = new Obejct”。只要强引用还存在,永远不会被GC清理。

软引用SoftReference

当Jvm内存不足时(内存溢出之前)会被回收。
SoftReference很适合用于实现缓存。

ReferenceQueue referenceQueue = new ReferenceQueue(); 
SoftReference softReference  = new SoftReference(new Man(), referenceQueue);  
/*If this reference object has been cleared, either by the program or by the garbage collector, then this method returns null.*/ 
softReference.get();  
//This method is invoked only by Java code; when the garbage collector enqueues references it does so directly, without invoking this method.
softReference.enqueue();    //入队列,即表示当前Reference对象已回收。
//Tells whether or not this reference object has been enqueued
softReference.isEnqueued();

弱引用WeakReference

弱引用的对象,只能生存到下一次GC前,当GC工作时,无论内存是否足够,都会回收掉弱引用关联的对象。
GC时,清空Reference对象的referent属性(即执行Reference.clear()),再将Reference对象加入该对象关联的ReferenceQueue中。

ReferenceQueue queue = new ReferenceQueue();
WeakReference ref = new WeakReference(new Man(), queue);

Assert.assertNotNull(ref.get());
Object obj = null;
obj = queue.poll();
Assert.assertNull(obj);

System.gc();

Assert.assertNull(ref.get());
Thread.sleep(10);// 入队列操作较慢,要等一下。
obj = queue.poll();
Assert.assertNotNull(obj);

虚引用PhantomReference

一个虚引用的对象,随时都会被gc。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被GC回收时收到一个系统通知。
phantomReference.get方法永远返回null, 当从内存中删除时,调用isEnqueued会返回true

为什么要用ReferenceQueue

Object obj = new Object();
Ref ref = new Ref(obj);

对于以上代码,我们希望当一个对象被gc掉的时候通知用户线程,进行额外的处理时,就需要使用引用队列ReferenceQueue。当一个obj被gc掉之后,其相应的包装类ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息,进行额外的处理。比如反向操作,数据清理等。

比如weakHashMap使用weakReference当作key来进行数据的存储,当key中的引用被gc掉之后,它不是自动将相应的entry给移除掉,而是我们调用get,size,put等方法时,weakHashMap从key的ReferenceQueue中获取引用信息,从而使得被gc掉的key值所对应的entry从map中被移除,然后再处理我们的业务调用。

类的初始化

对于有static final 修饰的变量的类,当引用该变量时,该类不会被构造。
对于有static变量的类,当第一次实例化该类,则静态变量会初始化,第二次不会。

父类静态属性 -> 父类静态块 -> 子类静态属性 -> 子类静态块 -> 父类属性 -> 父类块 -> 父类构造器 -> 子类属性 -> 子类块 -> 子类构造器   
相同等级下先定义的先初始化。

class SuperClass{  
    public SuperClass(){  
        System.out.println("SuperClass of constructor");  
        m();  
    }  
    public void m(){  
        System.out.println("SuperClass.m()");  
    }  
}  
public class SubClassTest extends SuperClass {  
    private int i = 10;  
    public SubClassTest(){  
        System.out.println("SubClass of constructor");  
        super.m();  
        m();  
    }  
    public void m(){  
        System.out.println("SubClass.m(): i = " + i);  
    }  
}

测试:

SuperClass t = new SubClassTest();

在生成对象时,父类调用的M()方法,不是父类的 M()方法,而是子类中被重写了的M()方法!!子类的private int i 也被父类访问到,和private的成员只能在本类使用的原则相违背。其实我们说的这条原则是编译期间所遵守的,在JAVA程序的编译期间,它只检查语法的合法性,在JAVA的JVM中,即运行期间,不管你声明的什么,对于JVM来说都是透明的,而动态引用是在运行期间执行的,所以能拿到SubClass的private成员,只是此时还没执行 i = 10,所以只能将i赋予初值0。

抽象类和接口

记住一个原则:接口目的是抽象,抽象类目的是复用
接口可以继承接口,一个抽象类或具体类可以实现多个接口(对于模块功能扩展,不需要修改原有接口)。
抽象类在实现接口中可以不用实现接口的所有方法。
接口的方法都是抽象方法。抽象类比接口灵活(弹性),多层抽象类的继承可以让整个主体更有扩展性和层次性。
当一个类实现一个接口时,如果不能完全实现就把这个类写作抽象类,就跟一个类如果不能实现他所继承的抽象类的全部抽象方法,那这个类也要命名为抽象类。
接口中定义变量必须为public static final,一般默认,可省略。

局部内部类

就是在对象的方法内部定义的类。而该局部内部类中的方法访问该局部内部类所在的方法中的局部变量时,该局部变量要加上final。
原因是:编译程序实现上的困难:内部类对象的生命周期会超过局部变量的生命期。当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。而内部类生命期,与其它类一样,只有没有其它人再引用它时,它才能死亡。
为什么局部变量定义为final可以呢?因为final变量为不可改变,编译程序具体实现:将所有的局部内部类对象要访问的final型局部变量,拷贝到局部内部类中
在Java8中,这种限制被新的概念“effectively final”取代了。它的意思是你可以声明为final,也可以不声明final但是要按照final来用,也就是一次赋值永不改变。即保证它加上final前缀后不会出编译错误。

注:不管变量是不是final,他的生命周期都在于{}中。

泛型

使得类型错误可以在编译时被捕获,而不是在运行时当作 ClassCastException 展示出来;消除强制类型转换,这使得代码更加可读。

类型擦除:
C#里面泛型无论在程序源码中、编译后的IL中(Intermediate Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,List与List就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,是真实泛型。 
Java泛型只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原生类型(Raw Type),并且在相应的地方插入了强制转型代码,因此对于运行期的Java来说,ArrayList与ArrayList就是同一个类。这种实现方法称为类型擦除,是伪泛型。

所以以下代码method()无法重载:

public class GenericTypes {  
  
   public static void method(List list) {  
      ......  
   } 
 
   public static void method(List list) {  
       ......
   }  
} 

 

方法的Signature属性是在字节码层面存储一个方法的特征签名,这个属性中保存了参数化类型的信息。虽然擦除法对方法体的源码的字节码进行类型擦除,但由于Signature,我们还是能通过反射API取得参数化类型。 

对象引用

一个父类对象的引用指向一个子类对象,从编译角度,该引用只能调用父类中定义的方法和变量;如果子类中重写了父类中的一个方法,那么会调用子类中的这个方法;变量不能被重写(覆盖),”重写“的概念只针对方法。
对象引用在内存中两个对象都生成了,子类、父类变量都生成了。

class Father {

    String name = "Father";


    public void func1() {
        func2();    // 若子类实现了func2(),则调用子类的func2()
    }


    public void func2() {
        System.out.println("Father func2");
    }

}

class Child extends Father {

    String name = "Child";


    public void func2() {
        System.out.println("Child func2");
    }

}

测试:

  Child child1 = new Child();
Father child2 = new Child();

child2.func1();     // Child func2

// 与方法重载不同,属性是无法重载的,属性跟类型走
System.out.println(child1.name);    // Child
System.out.println(child2.name);    // Father


Enum

Enum用于数据结构是稳定的,而且数据个数是有限的“数据集”。

//其内部实现
public abstract class Enum> implements Comparable, Serializable 


public enum Man {
    //wangliqiu、centifocus必定是public static final。
    wangliqiu, centifocus;

    public String name;
    public int age;
    public String sex;
}

//类比以上enum
public static class Man {
    public static final Man wangliqiu = new Man();
    public static final Man centifocus = new Man();

    public String name;
    public int age;
    public String sex;
}

示例:

public enum ColorEnum {
    red, //
    green, //
    yellow, //
    blue;
}

public static void main(String[] args) {
    ColorEnum colorEnum = ColorEnum.blue;
    switch (colorEnum) {
    case red:
        System.out.println("color is red");
        break;
    case blue:
        System.out.println("color is blue");
        break;
    }

    // 遍历 
    for (ColorEnum color : ColorEnum.values()) {
        System.out.println(color);
    }
    System.out.println("枚举索引位置:" + ColorEnum.red.ordinal());// 0

    // 枚举默认实现java.lang.Comparable接口,因为ENUM抽象类实现了。
    System.out.println(ColorEnum.red.compareTo(ColorEnum.green));// -1

}



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

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

相关文章

  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    AaronYuan 评论0 收藏0
  • JS对象和jQuery对象

    摘要:原文地址对象和对象的区别对象和对象使用说明,需要的朋友可以参考下。同样,对象也不能使用方法。学习开始就应当树立正确的观念,分清对象和对象之间的区别,之后学习就会轻松很多的。 原文地址:http://www.cnblogs.com/yellow... DOM对象和JQuery对象的区别 jQuery对象和DOM对象使用说明,需要的朋友可以参考下。jQuery对象和DOM对象第一次学习jQ...

    mtunique 评论0 收藏0
  • JavaScript对象

    摘要:对象的分类内置对象原生对象就是语言预定义的对象,在标准定义,有解释器引擎提供具体实现宿主对象指的是运行环境提供的对象。不过类型是中所有类型的父级所有类型的对象都可以使用的属性和方法,可以通过的构造函数来创建自定义对象。 对象 javaScript中的对象,和其它编程语言中的对象一样,可以比照现实生活中的对象来理解。在JavaScript中,一个对象可以是一个单独拥有属性和类型的实体。和...

    xavier 评论0 收藏0
  • JavaScript-对象

    摘要:对象是什么在中,一个对象就像一个单独拥有属性和类型的实体。一个杯子作为一个对象,杯子有颜色重量等属性。同样,对象也有属性定义它的特征。方法是关联到某个对象的函数,或者说,一个方法是一个值为某个函数的对象属性。 对象是什么 在JavaScript中,一个对象就像一个单独拥有属性和类型的实体。一个杯子作为一个对象,杯子有颜色、重量等属性。同样,JavaScript对象也有属性定义它的特征。...

    xeblog 评论0 收藏0

发表评论

0条评论

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