4种引用类型
/*
下面有关java的引用类型,说法正确的有?
正确答案: A B C D
对于一个对象来说,只要有强引用的存在,它就会一直存在于内存中
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,
在任何时候都可能被垃圾回收器回收。
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;
如果内存空间不足了,就会回收这些对象的内存
一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的空间
下面是4种引用类型
强引用
Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收
obj = null; //手动置null
只要强引用存在,垃圾回收器将永远不会回收被引用的对象
哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收
如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null
这样一来,JVM就可以适时的回收对象了
软引用
软引用是用来描述一些非必需但仍有用的对象
在内存足够的时候,软引用对象不会被回收,
只有在内存不足时,系统则会回收软引用对象
如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常
这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等
在JDK1.2之后,用java.lang.ref.SoftReference类来表示软引用
弱引用
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收
那些被弱引用关联的对象都会被回收
在JDK1.2之后,用java.lang.ref.WeakReference来表示弱引用
虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用
那么它就和没有任何引用一样,它随时可能会被回收,在JDK1.2之后,用PhantomReference类来表示
通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法
而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象
虚引用必须要和 ReferenceQueue 引用队列一起使用
*/
线程锁释放
/*
下列哪些操作会使线程释放锁资源?
正确答案: B C
sleep()
wait()
join()
yield()
sleep会使当前线程睡眠指定时间,不释放锁
yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁
wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态
join当前线程调用thread.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait,释放锁
*/
for循环执行顺序
class Test4 {
static boolean foo(char c) {
System.out.print(c); // ABDCBDCB
return true;
}
public static void main(String[] args) {
int i = 0;
for (foo('A'); foo('B') && (i < 2); foo('C')) {
i++;
foo('D');
}
}
/*
考察的相当于for循环执行顺序
其实foo(‘A’);就是初始化条件,只会执行一次,所以第一个打印的肯定是A
因为i=0;循环条件是i<2
由此可知循环i等于2的时候就会停止循环
所有0<2满足条件
接着会输出B,然后执行i++
i就变成1了,再输出D
再最后输出C,一次循环后的结果是:ABDC
第二次循环的开始是foo(‘A’);是初始条件所以不会执行,
直接从foo(‘B’)开始,输出B,
然后i为1,且小于2,此时循环体内再次执行i++
i的值为2了,再次输出D,最后输出C
第二次循环输出:BDC
然后循环再次执行for(foo(‘A’);foo(‘B’)&&(i<2);foo(‘C’))
直接输出B,i的值在第二轮循环后的值变成了2,2<2不成立,终止循环,输出B
*/
}
Integer类的常用方法
public static void main(String[] args) {
int a = Integer.parseInt("1024");
int b = Integer.valueOf("1024").intValue();
/*
a是整数类型变量,b是整数类对象
a是整数类对象,b是整数类型变量
a和b都是整数类对象并且它们的值相等
a和b都是整数类型变量并且它们的值相等
*/
System.out.println(judgeTypeInteger(a)); // true
System.out.println(judgeTypeInteger(b)); // true
System.out.println(a == b); // true
/*
intValue()是把Integer对象类型变成int的基础数据类型
parseInt()是把String 变成int的基础数据类型
valueof()是把String 转化成Integer对象类型,现在JDK版本支持自动装箱拆箱了
parseInt得到的是基础数据类型int,
valueof得到的是装箱数据类型Integer,
然后再通过valueInt转换成int,所以选择D
*/
}
三角函数
double d = Math.cos(42);
// double d1 = Math.cosine(42); // cosine方法不存在
double d2 = Math.cos(Math.toRadians(42));
double d3 = Math.cos(Math.toDegrees(42));
System.out.println(d + " " + d2 + " " + d3);
// -0.39998531498835127 0.7431448254773942 0.9993069281930212
// 科学计算器算出的结果是 0.74314482547739423501469704897426
/*
Math.cos为计算弧度的余弦值
Math.toRadians函数讲角度转换为弧度
toDegrees()是将弧度转换为角度
*/
GC垃圾回收机制
/*
以下说法正确的是
垃圾回收线程的优先级很高,以保证不再使用的内存将被及时回收
垃圾收集允许程序开发者明确指定释放哪一个对象
垃圾回收机制保证了JAVA程序不会出现内存溢出
进入”Dead”状态的线程将被垃圾回收器回收
以上都不对
正确答案:E
A:垃圾回收在jvm中优先级相当相当低
当程序运行时,至少会有两个线程开启启动,一个是我们的主线程
一个时垃圾回收线程,垃圾回收线程的priority(优先级)较低
B:垃圾收集器(GC)程序开发者只能推荐JVM进行回收,但何时回收,回收哪些,程序员不能控制
垃圾回收器会对我们使用的对象进行监视,当一个对象长时间不使用时
垃圾回收器会在空闲的时候(不定时)对对象进行回收,释放内存空间
程序员是不可以显示的调用垃圾回收器回收内存的
但是可以使用System.gc()方法建议垃圾回收器进行回收,但是垃圾回收器不一定会执行
C:垃圾回收机制只是回收不再使用的JVM内存,如果程序有严重BUG,照样内存溢出
D:进入DEAD的线程,它还可以恢复,GC不会回收
进入dead的线程最后会调用finilized方法,有可能是dead线程重新复活。所以d错
*/
值传递开辟内存空间
/*
下面这段java代码,当 T 分别是引用类型和值类型的时候
分别产生了多少个T对象和T类型的值()
T t = new T();(值类型时:T t;)
Func(t);
Func 定义如下:
public void Func(T t) { }
正确答案: D
1 1
2 1
2 2
1 2
引用类型作为函数的参数时,复制的是引用的地址,不会产生一个新的T
而如果T是值类型,其作为函数实参时会复制其值,也就是产生了一个新的T
所以D选项正确
值类型即八大基础类型,基础类型在使用时是从常量池中获取
更严谨的而言其实是在-128~127之间 使用时是从常量池中获取,那么在使用的时候将常量池中的地址重复利用
但是在限制范围之外,得到的地址就会发生变化 代码为证
*/
class Test7 {
public static void main(String[] args) {
int x1 = 127;
int x2 = 129;
int identityHashCode = System.identityHashCode(x1);
System.out.println("传递之前:x1 identityHashCode = "+identityHashCode);
identityHashCode = System.identityHashCode(x2);
System.out.println("传递之前:x2 identityHashCode = "+identityHashCode);
System.out.println("-----------------------------------------");
method(x1);
method(x2);
}
public static void method(int x) {
int identityHashCode = System.identityHashCode(x);
System.out.println("传递之后:x identityHashCode = "+identityHashCode);
}
/*
传递之前:x1 identityHashCode = 460141958
传递之前:x2 identityHashCode = 1163157884
-----------------------------------------
传递之后:x identityHashCode = 460141958
传递之后:x identityHashCode = 1956725890
x1前后得到的hashCode相同
x2前后得到的hashCode不相同
总之,我还是认为值类型的不能称之为对象,虽然超过缓存范围限制时重新开辟了空间,
但是不能与引用类型混为一谈
我坚持值类型传递创建了0个对象,开辟了2个内存地址
*/
}
Java创建对象的5种方式
/*
Java有5种方式来创建对象:
1、使用 new 关键字(最常用): ObjectName obj = new ObjectName();
2、使用反射的Class类的newInstance()方法: ObjectName obj = ObjectName.class.newInstance();
3、使用反射的Constructor类的newInstance()方法:
ObjectName obj = ObjectName.class.getConstructor.newInstance();
4、使用对象克隆clone()方法: ObjectName obj = obj.clone();
5、使用反序列化(ObjectInputStream)的readObject()方法:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
ObjectName obj = ois.readObject();
}
*/