Java的理解
- 平台无关性
- GC 垃圾回收机制
- 语言特性:反射、范型、lambda表达式等
- 面向对象:多态、继承、封装
- 类库:集合、并发库、IO库等
- 异常处理
平台无关性
Jvm可以从软件层屏蔽不同的操作系统在底层硬件与指令上的区别。
.java文件通过javac编译生成.class文件,.class文件中包含:编译生成的二进制码、java类中的属性、方法和静态属性。可以通过java自带的javap命令反编译查看.class文件,了解java编译器内部机制。
- javap指令(javap -help查看), -c 对代码进行反汇编。
JVM架构
Java虚拟机JVM,抽象化的、运行在内存中的虚拟化计算机,通过模拟仿真各种计算机功能。JVM屏蔽了与具体操作系统平台相关的信息,使得java编译后可以在各种平台运行。
Class Loader(类装载系统):依据特定格式,加载class文件到Runtime Data Area。
Execution Engine(字节码执行引擎):对命令进行解析。
Native Interface(本地方法接口):融合不同开发语言的原生库为java所用。
Runtime Data Area(运行时数据区):JVM内存空间结构模型。
JVM如何加载class文件?
Java反射机制
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有方法和属性;对于任意一个对象都能够调用任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
定义反射类Robot,包括私有属性name、公共方法sayHi、私有方法throwHello。
package com.Interview.javabasic;
public class Robot {
private String name;
public void sayHi(String helloSentence){
System.out.println(helloSentence + "" +name);
}
private String throwHello(String tag){
return "hello" + tag;
}
}
定义反射实例类,通过forName获取反射类、newInstance实例化反射类、getDeclaredMethod和getMethod获取反射类的方法、getDeclaredField获取反射类的属性、invoke调用反射类的方法并且可以传入参数。
package com.Interview.javabasic;
import javax.swing.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectSample {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//forName根据类的路径获取类对象
Class rc = Class.forName("com.Interview.javabasic.Robot");
//通过newInstance获取类的实例,因为newInstance返回的实例类型是范性,需要强转。
Robot r = (Robot) rc.newInstance();
System.out.println("class name "+rc.getName());
//getDeclaredMethod能够获取反射类的所有包括公共和私有方法,但是不能获取继承的方法和实现接口的方法。
Method getHello = rc.getDeclaredMethod("throwHello",String.class);
//getMethod只能获取公共public方法,但是可以获取反射类继承的方法和实现接口的方法。
Method sayHi = rc.getMethod("sayHi", String.class);
Field name = rc.getDeclaredField("name");
//反射类的throwHello为私有方法、name为私有属性,因此需要设置setAccessible为true
getHello.setAccessible(true);
name.setAccessible(true);
//给name赋值,需要传入实例化的反射类对象
name.set(r,"alice");
//使用Object接受返回的值,invoke()返回的是Object对象,
Object str = getHello.invoke(r,"Bob");
sayHi.invoke(r,"welcome");
System.out.println("getHello result" + str);
}
}
类从编译到执行的过程
反射获取类的class对象,必须先获取该类的字节码文件对象。
- 编译器将Robot.java源文件编译为Robot.class字节码文件。
- ClassLoader将字节码(byte数组格式)转换为JVM中的Class对象。
- JVM利用Class对象实例化为Robot对象。
ClassLoader简介
ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。他是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载近系统,然后交给Java虚拟机进行连接、初始化等操作。
ClassLoader的种类
- BootStrapClassLoader:C++编写,加载核心库java.*,由JVM实现。
- ExtClassLoader:Java编写,加载扩展库javax.*,可以将自定义的class进行加载。
- AppClassLoader:Java编写,加载程序所在目录。用于加载ClassPath路径下的内容 ,例如上述的Robot.class和ReflectSample.class文件。
- 自定义ClassLoader:Java编写,定制化加载。
findClass()根据名称和路径加载.class字节码,然后它会调用defineClass()解析定义clss字节流并返回class对象。
自定义ClassLoader实例
目的:自定义一个类加载器,实现加载自定义claa文件的功能。
流程:
-
1.在工程以外创建一个Wail类(Wail.java),使用javac编译为Wail.class文件。
public class Wail{ static{ System.out.println("Hello wail");