目录
一、为什么非静态方法不能访问静态方法、静态成员?
二、普通代码块、静态代码块、构造器(constructor)的执行顺序
三、synchronized锁的是什么
四、synchronized关键字和volatile关键字的区别
五、Java中的类加载器
1、概念
2、JVM中的类加载器的分类:
六、关于Java内存局域
七、Object类中的方法有哪些
1.toString()
2.wait()、wait(long timeout)、wait(long timeout,int naos)
3.notify()和notifyAll()
4.finalize()
5.equals()
6.hashCode()
7.getClass()
8.clone()
一、为什么非静态方法不能访问静态方法、静态成员?
因为静态方法、静态成员是随着类加载而加载的,而非静态方法、非静态成员是在类创建(new)好过后,才会有的。(加载时间不一样)
静态方法、静态成员的生命周期比非静态的要早,消亡的时间要晚。
二、普通代码块、静态代码块、构造器(constructor)的执行顺序
静态代码块>普通代码块>构造器(constructor)
因为静态代码块是随着类的加载而加载的,普通代码块在创建对象时才会被加载,构造器执行之后,代表对象真正地创建成功,是最后一步。
三、synchronized锁的是什么
加锁实际上就是在锁对象的对象头中写入当前线程id,每个线程要想调用这个同步方法,都会先去锁对象的对象头看看当前线程id是不是自己的。
对于静态方法来说,锁的是T.class(T为类名),这个类的字节码文件;非静态方法锁的是this,也就是类的实例对象;代码块锁的是括号里的对象。
注意:synchronized是可重入锁。也就是说当线程访问对象的同步方法时,在调用其他同步方法时无需再去获取其访问权。
四、synchronized关键字和volatile关键字的区别
- volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其他各种优化之后执行效率有了显著提升,实际开发中使用synchronized关键字的场景还是更多一些。
- 多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞
- volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都可以保证。
- volatile关键字主要用于解决变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性。
五、Java中的类加载器
1、概念
1、概念
Java类加载器是Java运行时环境的一部分,负责动态加载Java类到JVM的内存空间中。每个Java类必须由某个类加载器装入到内存中。每个类加载器都有一个父类加载器(BootStrap引导类加载器没有)。
2、JVM中的类加载器的分类:
(1)、Bootstrap ClassLoader :引导类加载器。这个加载器很特殊,它不是JAVA类,因此它不需要被别人加载,它嵌套在JVM内核里,也就是说JVM启动的时候BootStrap就启动了,它是C++写的二进制代码,可以加载别的类。这也是为什么System.class.getClassLoader()结果为null的原因,因为它不是JAVA类,所以它的引用返回null。负责加载核心Java库,存储在
(2)、 Extension ClassLoader:扩展类加载器。它用来加载 Java 的扩展库。Java虚拟机的实现会提供一个扩展库目录,扩展类加载器在此目录里面查找并加载 Java 类,主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
(3)、System ClassLoader:系统类加载器。主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
(4)、User Custom ClassLoader:用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
六、关于Java内存局域
(1)、程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器(偏移地址),Java编译过程中产生的字节码有点类似编译原理的指令,程序计数器的内存空间存储的是当前执行的字节码的偏移地址,每一个线程都有一个独立的程序计数器(程序计数器的内存空间是线程私有的),因为当执行语句时,改变的是程序计数器的内存空间,因此它不会发生内存溢出 ,并且程序计数器是jvm虚拟机规范中唯一一个没有规定 OutOfMemoryError 异常 的区域;
(2)、java虚拟机栈:线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。 没有类信息,类信息是在方法区中;
(3)、java堆:对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组;
(4)、方法区:属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
七、Object类中的方法有哪些
1.toString()
返回一个String类型的字符串,用于描述当前对象的信息。
2.wait()、wait(long timeout)、wait(long timeout,int naos)
注意: 在多线程环境下才会使用wait()
注意: 在多线程环境下才会使用wait()
wait()的作用:让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒并进入“就绪状态”。
wait(long timeout)的作用:让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒并进入“就绪状态”。
3.notify()和notifyAll()
notify()方法:针对多线程,在wait()方法后面使用,用于唤醒该对象等待的某个线程
notifyAll()方法:针对多线程,在wait()方法后面使用,用于唤醒该对象等待的所有线程
4.finalize()
java允许在类中定义一个名为finalize()的方法。
它的工作原理是:在垃圾回收器准备好释放对象占用的存储空间前,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
5.equals()
Object中的equals()方法是直接用来判断两个对象指向的内存空间是不是同一块。如果是同一块内存地址,则返回true。
6.hashCode()
作用:返回字符串的哈希码值,用于判断两个对象的地址是不是同一个。
注意:1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
2、如果两个对象不equals,他们的hashcode有可能相等。
3、如果两个对象hashcode相等,他们不一定equals。
4、如果两个对象hashcode不相等,他们一定不equals。
7.getClass()
返回Object运行时的类,不可重写,要调用的话,一般和getName()联合使用,如getClass().getName();
8.clone()
通过clone方法复制一个对象。克隆又分为浅克隆、深克隆。
- 浅克隆:原对象和克隆对象不同,但对象内的成员引用相同
- 深克隆:原对象和克隆对象不同,且对象内的成员引用也不同



