Java第二周:
C是面向过程的 C++是面向对象的(混合)
- 可以叫Java是C-plus-plus的minus-minus版本
- System.out.println()
–System是个类,Out是个对象,println是个方法 - 对javase来说rt.jar很重要
–在jre/lib里面的runtime.jar,包含了System.class - Portable by jvm
- 强类型语言 声明变量要先使用
- 虽然我们说everything is an object
–但是有些基本类型不是对象 - Java在语言级支持多线程
–Java依赖于虚拟机 而C这种靠的是OS
–线程合体 = 进程 线程比较小可独立运行
–方便进程与系统去管理他们,缺少一个线程 经常依旧运行其他的线程
–线程在代码里面是什么?
–比如一个等待响应的代码,如果有多个数据要等,那一个个等太耗时间,这个时候使用多线程可以同时等待 - 可以使用Java监视和管理控制台来看jvm
–在jvm中就是需要很多的线程来支持,这样,除了出事的线程外,该干干嘛
–但是 高并发的debug很容易不可再现! - 在rt.jar的concurrent可以看到多线程包

-
垃圾回收-内存管理
–垃圾回收避免内存泄漏,但是也不是完全避免哈~
–栈的引用指向了堆的东西 就是可达的,而不可达的就是没用的
–而实现的理解就是 有个计数器 当一个对象的引用计数为zero 就无用了
–gc就会想办法把他回收掉
----什么是内存泄漏?
–useless的对象 却是reachable的,这样就没被gc回收掉 -
如果有一组堆内互相指向对方的对象
–没有’外力’拉着他们 依旧会gc回收
----能提供外力的是什么?
–Gc Roots
–可以理解为栈的引用拉着堆内的对象
–可以用可视化工具来侦查源头(回溯) -
访问范围修饰符:
–public> ’ ’ >private>protected
–Top class only use public and none
–Inner class可以用private -
为什么要封装类?
–为什么System类是private的?
–因为不想要你用啊!!,只让你调用系统的方法,不给你整对象 -
Object类非常最要
–it is a root of the class hierarchy
–在Object中public方法在任何类都可以用
–getclass()
–toString()【return 类名+@+hashcode】
–equals()【比较的是地址】
–hashcode()【return 地址【
–notify()*2
–wait()*3
–finalize() -
要知道Object中缺省的方法是什么 然后知道如何去修改他们
-
大小写敏感的java真的很敏感的呢
-
Main方法的签名是必须的 而传入的数组是get命令行的option
-
Primitive数据类型
–引用类型有无穷种
–int4 byte1 short2 long8
–float double
–boolean char2 -
Java的字符对Unicode很支持
–每个字符对应唯一的符号
–GB1312是JAVA不支持的嘛?
–桂老板解答了,JAVA内部都是unicode,导入的时候会自动转码 -
Boolean存的就是true和false
–(最好不要用0和1) -
对11与12进行补充:
可达性分析解决的问题
垃圾回收的可达性分析算法:解决了循环引用导致引用计数失效的问题。引用计数可以类比为:几个重物之间互相用绳子连起来,记录每个重物所连接的绳子数。当某个重物所连接的绳子数不为0时,判断重物没有落地(落地就是被垃圾回收)。但是这样的问题在于,如果几个重物存在循环引用,而没有稳定向上的拉力,重物本应该落地,但是因为引用计数不为0,导致没有落地。如图所示:、
由此可见,垃圾回收可以有一个新的思路:从稳定的拉力源开始往下找,查看对象是否可以访问到。**如果不能访问到,说明对象也不能被利用了,就被回收掉。这里的“稳定的拉力源”,被称为根集(GC Roots)。一般来说,GC Roots有几种来源:
1.虚拟机栈中的引用的对象
2.方法区中的类静态属性引用的对象
3.方法区中的常量引用的对象
可以看到,栈帧随着函数的执行会弹出,所以局部变量的引用在函数执行结束后就没了,对象也随之被回收;方法区因为作为持久带,很少做垃圾回收,所以静态属性引I用的对象总会有一个稳定的拉力来源,用多了就容易造成内存泄漏。可达性分析过程
Java所有类的祖宗类Object中有一个方法,叫做 finalize(),也就是说,所有类的对象中都会有这么一个函数,这个函数在垃圾回收中起作用。事先说明一 点: finalize()很不可靠,不要人为调用它。由GC自动调用。finalize主要为GC做一些清除或清扫工作。
1.从GC Roots中的引用出发,按照路径往下找,记 录可到达对象;扫描完毕后,可以发现不可达对 象。这一步叫做可达性分析;
2.不可达的对象,并不马上被垃圾回收,后面还要经 过两次标标记;
3.第一次标记:查看对象是否有必要执行finalize(),如果有必要执行,则调用;如果没有必要,则直接回收,进行第一次标记(没必要执行的情况是:如果对象所在类没有重写finalize(),或者finalize(已经被执行过);
4.如果对象被判定为有必要执行finalize(),则这些对象被放进个队列——F-Queue,虚拟机会建—个优先级很低的线程——Finalizer,去一个个调用这些对象的finalize()方法。但是GC并不承诺会等finalize()全部执行结束才回收对象,因为 finalize()内部可能会出现死循环的情况。
5.如果finalize()执行完了,对象经历了两次标记,那就死定了,会被垃圾回收掉。
那么,如何利用finalize()从垃圾回收流程中逃出去? 在此过程中重新找个对象指向此对象就可以。
代码例子:
public class FinalizeTest {
public static Myclass reference =null;
@Test
void Test() throws InterruptedException {
FinalizeTest.reference = new Myclass();
FinalizeTest.reference = null;
system.gc();
Thread.sleep(500);
if(FinalizeTest.reference !=null){
system.out.println("I am still alive! ");
}else{
system. out.println("I am dead! ");
}
//再来一遍
FinalizeTest.reference = null;
system.gc();
if(FinalizeTest.reference != null){
system.out.println("I am still alive! ");
}else{
system.out.println("I am dead! ");
}
}
}
class Myclass{
public int status = 1;
@override
protected void finalize() throws Throwable {
super.finalize();
system.out. println("finalize(执行完毕.............");
FinalizeTest .reference = this;
//将当前对象连接到方法区的静态变量
}
}
运行结果:
可以看到,第一次逃掉了,第二次因为finalize()已经被执行,所以直接被垃圾回收了。
25.纠错1.0
26.纠错2.0
首先是判断为不可达,并且finalize方法没有被重写,这两个条件都要被满足,才会放到f-queue里面等待被finalizer执行finalize。
这样做的逻辑在于,如果用户自己重写了finalize,意味着他想做一些自定义的清理工作,放到finalize里面。如果没有重写,原本的这个方法什么也不会做,并且此时如果判断不可达,那就可以直接回收掉。
需要第二次标记的原因是,gc会跑上去瞄一眼,如果标记了两次那就直接吃掉,如果此时对象被标记了一次之后自救了,那还是可以复活。
如果第二次运行的时候,看到标记1就立马吃掉,那就不能复活了。
直接回收的条件:
- 不可达
- 没有override finalize方法
但是,gc只是个扫地机,不太能相信,害怕的话建议自己去执行。
此外,就算你写个死循环,时间太长了gc也会干掉你的对象。
而且你也不能无限标记无限复活,gc只给你一次面子。
(有错就改,希望大家多提意见)