类加载全过程
1.new 一个类对象
2.调用类的静态成员(除了final常量)和静态方法
3.使用java.lang.reflect包的方法对类进行发射调用
4.当虚拟机启动,java hello 则一定会初始化hello类 说白了就是先启动main方法所在的类
5.当初始化一个类,如果其父类木有被初始化 则先会初始化他的父类
类的被动引用(不会发生类的初始化)
1.当访问一个静态域时, 只有真正声明这个域的类才会被初始化
通过子类引用父类的静态变量 不会导致子类初始化
2.通过数据定义类引用 不会触发此类的初始化
3.引用常量不会触发此类的初始化(常量在编译阶段就存了调用类的常量池中了)
被不同加载器加载的同一个类 被视为不同的类
案例 自定义类加载器
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 自定义文件系统类加载器
* @author 尚学堂高淇 www.sxt.cn
*
*/
public class FileSystemClassLoader extends ClassLoader {
//com.bjsxt.test.User --> d:/myjava/ com/bjsxt/test/User.class
private String rootDir;
public FileSystemClassLoader(String rootDir){
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
//应该要先查询有没有加载过这个类。如果已经加载,则直接返回加载好的类。如果没有,则加载新的类。
if(c!=null){
return c;
}else{
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); //委派给父类加载
} catch (Exception e) {
//e.printStackTrace();
}
if(c!=null){
return c;
}else{
byte[] classData = getClassData(name);
if(classData==null){
throw new ClassNotFoundException();
}else{
c = defineClass(name, classData, 0,classData.length);
}
}
}
return c;
}
private byte[] getClassData(String classname){ //com.bjsxt.test.User d:/myjava/ com/bjsxt/test/User.class
String path = rootDir +"/"+ classname.replace('.', '/')+".class";
//IOUtils,可以使用它将流中的数据转成字节数组
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try{
is = new FileInputStream(path);
byte[] buffer = new byte[1024];
int temp=0;
while((temp=is.read(buffer))!=-1){
baos.write(buffer, 0, temp);
}
return baos.toByteArray();
}catch(Exception e){
e.printStackTrace();
return null;
}finally{
try {
if(is!=null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(baos!=null){
baos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
案例:改变当前线程的加载器
/**
* 线程上下文类加载器的测试
* @author 尚学堂高淇 www.sxt.cn
*
*/
public class Demo05 {
public static void main(String[] args) throws Exception {
ClassLoader loader = Demo05.class.getClassLoader();
System.out.println(loader);
ClassLoader loader2 = Thread.currentThread().getContextClassLoader();
System.out.println(loader2);
Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("d:/myjava/"));
System.out.println(Thread.currentThread().getContextClassLoader());
Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("com.bjsxt.test.Demo01");
System.out.println(c);
System.out.println(c.getClassLoader());
}
}
1.内部类仍然是一个独立的类 ,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号
2.内部类可以使用修饰符(public ,protected, default,private)
静态内部类的基本用法:
a.静态内部类可以包含静态成员, 非静态成员
b.静态内部类可以直接调用外部类的静态属性,静态方法,但不能调用外部类的普通属性 普通方法
c.在不相关的类中,可以直接创建静态内部类的对象(不需要通过所在外部类)
d.静态内部类实际上和外部类联系很少,也就是命名空间上的联系
成员内部类(普通内部类)
成员内部类基本用法:
a.成员内部类就像一个成员变量一样存在于外部类中
b.成员内部类可以访问外部类的所有成员(包含:private)
c.成员内部类的this指内部类对象本身,要拿到外部类对象可以使用:外部类名+.this
成员内部类的对象是一定要绑到一个外部类的对象上的,因此:创建成员内部类对象时需要持有外部类对象的引用。
因此, 要先有外部类对象, 后有成员内部类对象
d.成员内部类不能有静态成员
e.成员内部类对象的创建方式:
外部类内部 Inner inner= new Inner()
外部类外部 Inner inner= new Outer().Inner();
方法类基本用法:
a.方法内部类的地位和方法的局部变量的位置类似
因此不能修饰局部变量的修饰符也不能修饰局部内部类,譬如 public, private, protected,static transient等
b.方法内部类只能在声明的方法内是可见的
因此定义局部内部类之后,想用的话就要在此方法内直接实例化,记住这里顺序不能反了,一定要先声明后时候,否则编译器会说找不到
c.方法内部类不能访问定义它的方法内的局部变量, 除非这个变量被定义为final
本质原因;局部变量和方法内部类生命周期不一致
d.方法内部类只能包含非静态成员
匿名内部类:
1.匿名内部类的实例化方法:new SomeInterfaceOrClass(){}
意思是创造一个实现(继承)了 SomeInterfaceOrClss的类对象
2.根据声明的位置, 判断匿名内部类是成员内部类还是方法内部类
注: 一般是 方法内部类 具备方法内部类的特征
三种使用方法; a.继承式 b接口式 c.参数式
案例:内部类
public class Demo02{
public static void main(String[] args){
Outer02.StaticNestedClass osic= new Outer02.StaticNestedClass(); //在不相关的类中,可以直接创建静态内部类的对象(不需要通过所在外部类)
// 或者 这种方式要import xxx.xxx.Outer02.StaticNestedClass;
StaticNestedClass osic= new StaticNestedClass();
}
}
class Outer02{
int c =5;
static int d=5;
void ttt(){
StaticNestedClass sic= new StaticNestedClass();
}
//静态内部类
static class StaticNestedClass{
int a=0; //静态内部类可以包含静态成员, 非静态成员
static int b=0; //静态内部类可以包含静态成员, 非静态成员
public void test(){
System.out.println(d); //静态内部类可以直接调用外部类的静态属性,静态方法,
System.out.println(c); //但不能调用外部类的普通属性 普通方法
}
}
//普通内部类(成员内部类)
private class FieldInnerClass{
static int e=0; //成员内部类不能有静态成员
}
void syaHello()
{
//方法内部类(局部内部类)
class LocalClass{
}
}
//匿名内部类
Runable runable =new Runable(){ //两个作用,定义了匿名内部类的类体,船舰了匿名内部类的一个实例
@Overide
public void run() {
}
};
}