JAVA基础8(代码剖析)

时间:2022-05-09 11:52:47

类加载全过程
 1.new 一个类对象
 2.调用类的静态成员(除了final常量)和静态方法
 3.使用java.lang.reflect包的方法对类进行发射调用
 4.当虚拟机启动,java hello 则一定会初始化hello类 说白了就是先启动main方法所在的类
 5.当初始化一个类,如果其父类木有被初始化 则先会初始化他的父类
 
类的被动引用(不会发生类的初始化)
1.当访问一个静态域时, 只有真正声明这个域的类才会被初始化
  通过子类引用父类的静态变量 不会导致子类初始化
2.通过数据定义类引用 不会触发此类的初始化
3.引用常量不会触发此类的初始化(常量在编译阶段就存了调用类的常量池中了)


JAVA基础8(代码剖析)


JAVA基础8(代码剖析)


JAVA基础8(代码剖析)


JAVA基础8(代码剖析)


被不同加载器加载的同一个类 被视为不同的类

案例 自定义类加载器

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();
}
}

}
}

JAVA基础8(代码剖析)


案例:改变当前线程的加载器

/**
* 线程上下文类加载器的测试
* @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() {
}
};

}