Fork me on GitHub

JavaSE Day21

JavaSE Day21 发射 类加载


类加载

一个程序只能有一个main方法

类的生命周期

类的加载过程:加载、连接、初始化

把类的字节码文件 加载到 方法区的内存中。同时在堆内存中生成一个Class类型的类对象(此对象,相当于这个类的模板文件);

  1. 类的装载:查找和导入Class文件;

  2. 类的连接:把二进制数据 合并到JRE中;此过程分为三个步骤:

    1. 验证
      验证字节码文件的格式。
    2. 准备
      为类中的静态变量开辟空间,并且进行默认初始化;
    3. 解析
      把符号引用 替换成指针;
  3. 初始化:对静态变量进行声明处或者静态块处初始化;

  4. 使用

  5. 卸载

类的初始化

  1. 当创建某个类的新实例时;
  2. 当调用某个类的静态成员;
  3. 当初始化某个子类时,该子类的所有父类会被初始化
  4. 当使用反射方法强制创建某个类或接口的对象时
  5. 当虚拟机java命令运行启动类(主方法所在的类),会加载主类;

注意:static final类型的变量,并且在编译期能够确定值的,是不会引起初始化的情况

类加载器

根类加载器

主要作用:

  1. 负责加载系统的核心类库
  2. Java/jre/lib目录下的所有类库

扩展类加载器

主要作用:加载 Java/jre/lib/ext目录下的所有类库

系统类(应用类)

主要作用:加载 classpath路径下的类 当前路径下的类

自定义类加载器(继承 ClassLoader类)

主要作用:加载自己路径下的类

加载器之间的关系

package day21;


public class Demo3 {
	public static void main(String[] args) {
		// 获得Demo3的类加载器
		// AppClassLoader 系统类加载器(应用类记载器)
		ClassLoader loader = Demo3.class.getClassLoader();
		System.out.println(loader);
		// ExtClassLoader 扩展类加载器
		System.out.println(loader.getParent());
		// null 根类加载器 
		System.out.println(loader.getParent().getParent());
		
	}
}

加载类时用的是父类委托机制

使用类加载器的顺序
根加载器 <- 扩展类加载器 <- 系统类加载器 <- 用户类加载器

先找父类能加载就加载了并返回个对象(加载成功),父类不能加载就原路返回找子类 看能不能加载;

加载类的两种方式

package day21;




public class TestLoader1 {
	public static void main(String[] args) throws ClassNotFoundException{
		// 加载了类
		ClassLoader.getSystemClassLoader().loadClass("day21.TestLoader1");
//		ClassLoader.getSystemClassLoader().loadClass("day21.Demo4");
		
		// 类的初始化
		Class.forName("day21.Demo4");
		//            类名                         是否初始化,true表示要初始化              类加载器
		Class.forName("day21.Demo4",true,ClassLoader.getSystemClassLoader());
	}
}

要用用户类加载器,说明java文件的字节码文件不在classpath目录下;

package day21;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

class MyLoader extends ClassLoader{
	String path;
	MyLoader(String path){
		this.path = path;
	}
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		Class c = null;
		// d:/data1/Hello.class
		// path -> d:/data/  name -> Hello
		path = path+name.concat(".class");
		File f = new File(path);
		FileInputStream fin = null;
		try {
			fin = new FileInputStream(f);
			byte[] b = new byte[fin.available()];
			int len = fin.read(b);
			// 解析成方法区能够识别的数据结构
			 c = this.defineClass("Hello", b, 0, len);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if(fin != null){
				try {
					fin.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		
		
		
		return c;
	}
	
	
}
public class TestMyLoader {
	public static void main(String[] args) throws ClassNotFoundException {
		//                           d:data1/Hello.class
		MyLoader loader = new MyLoader("d:/data1/");
		Class.forName("Hello",true,loader);
		
	}
}

安全管理器

重写SecurityManager来控制我的程序的安全性;

package day21;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

// 自定义安全管理器
class MySecurity extends SecurityManager{

	@Override
	public void checkRead(String file) {
		// TODO Auto-generated method stub
		if(file.endsWith(".java")){
			throw new SecurityException("不允许读java文件");
		}
	}
	
}

public class TestFileInputStream {
	public static void main(String[] args) throws IOException {
		// 设置自己的安全管理器
		System.setSecurityManager(new MySecurity());
		
		File f = new File("d:/data1/Hello.java");
		FileInputStream fin = new FileInputStream(f);
		int temp = fin.read();
		System.out.println((char)temp);
		fin.close();
		
	}
}

反射

(在运行期)动态的获得类(字节码文件中)中的数据;

加载类的三种方法

// 获得字节文件对应的对象
		// 1.
//		Class<Person> c = Person.class;
		
		// 2. 匹配上限类 和 上限类的子类
//		Class<? extends Person> c = new Person().getClass();
		
		// 3.
		Class<?> c = Class.forName("day21.Person");

获得属性

Field属性

  1. getFields 获得所有属性,但是是共有的
  2. getDeclaredFields() 获得所有属性,包括私有的;
  3. getDeclaredField(属性名) 获得单个属性
  4. Set()给属性赋值
  5. Get(对象) 获得属性的值

获得方法:

Method属性

  1. getDeclaredmethods() 获得所有方法
  2. getDeclaredMehtod(方法名,参数类型列表) 获得单个方法
  3. invoke(对象,实参列表) 调用方法

获得构造器

Constructor属性

  1. getDeclaredConstructors();获得所有构造器
  2. getDeclaredConstructor(参数类型列表):获得单个构造
  3. newInstance(实参列表) 调用构造器

实例

package day21;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;

class Person{
	private int no;
	 public String name;
	 public Person(){
		 System.out.println("无参构造");
	 }
	 public Person(int no,String name){
		 this.no = no;
		 this.name = name;
		 System.out.println("带参构造:"+this.no+","+this.name);
	 }
	 
	 public void show(){
		 System.out.println("无参方法show");
	 }
	 public String disp(int n,String str){
		 return "带参方法"+n +str;
	 }
	
}
public class TestPerson {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		// 从字节码文件获得信息
		// 获得字节文件对应的对象
		// 1.
//		Class<Person> c = Person.class;
		
		// 2. 匹配上限类 和 上限类的子类
//		Class<? extends Person> c = new Person().getClass();
		
		// 3.
		Class<?> c = Class.forName("day21.Person");
		// ---------获得属性-----------------
//		Field[] fs = c.getFields();// 共有的
		Field[] fs = c.getDeclaredFields();//全部属性
		for(Field f:fs){
			System.out.println(f.getName());
			System.out.println(f.getType());
			System.out.println(Modifier.toString(f.getModifiers()));// 访问权限
		}
		//设置 安全管理器
//		System.setSecurityManager(new SecurityManager());
		
		// 获得单个属性
		Field f = c.getDeclaredField("no");
		f.setAccessible(true);// 破坏封装,设置访问权限;为true表示能修改私有属性;
		Object obj = c.newInstance();
		f.set(obj,22);
		System.out.println(f.get(obj));
		
		// -----------方法--------------
		java.lang.reflect.Method[] ms = c.getDeclaredMethods();
		for(java.lang.reflect.Method m : ms){
			System.out.println(m.getName());
			System.out.println(m.getReturnType());
			System.out.println(Arrays.toString(m.getParameters()));
			
		}
		// 无参就不用写参数
		java.lang.reflect.Method m1 = c.getDeclaredMethod("show");
		m1.invoke(obj);
		
		java.lang.reflect.Method m2 = c.getDeclaredMethod("disp", int.class,String.class);
		String str = (String) m2.invoke(obj,123,"abc");
		System.out.println(str);
		// ----------------获得构造器------------------
		System.out.println("构造器");
		Constructor[] crs = c.getDeclaredConstructors();
		for(Constructor cr:crs){
			System.out.println(cr.getName());
			System.out.println(Arrays.toString(cr.getParameters()));
		}
		
		Constructor cr1 = c.getDeclaredConstructor();
		cr1.newInstance();
		Constructor cr2 = c.getDeclaredConstructor(int.class,String.class);
		cr2.newInstance(11,"Tom");
	}
}

注解

注解的概念和作用;

作用是给编译器提供信息;

JDK中提供的标准注解;

  1. @Override
  2. @Depredcated 已过时的;
  3. @Suppresswarnings 镇压警告;
    1. All 镇压所有警告
    2. Rawtypes
    3. Unchecked
    4. Unused
    5. Serial 序列化 版本号的镇压警告;
  4. @FunctionalInterface
package day21;

import java.util.ArrayList;
import java.util.List;

class Parent{
	int x;
	@Deprecated
	public void sf(){}
	public void f(){
		int n = 34;
		System.out.println(n);
	}
	
}

class DemoA{
	@SuppressWarnings("unchecked")
	public void show(){
		@SuppressWarnings({"rawtypes","unused"})
		List list = new ArrayList();
		list.add("abc");
		list.add(123);
	}
}
class Child extends Parent{
	// 注解 作用是给编译器提供信息;
	@Override
	public void f() {
		// TODO Auto-generated method stub
		super.f();
	}
	
}
public class TestAnno1 {
	public static void main(String[] args) {
		Person s = new Person();
	}
}

JDK的元注解

在定义注解时,需要确定注解修饰的类型、运行的范围等参数,就需要元注解来修饰自定义注解;

@Target

修饰哪些程序元素

  1. CONSTRUCTOR 构造方法声明
  2. FIELD 字段声明(包括枚举常量)
  3. LOCAL_VARIABLE 局部变量声明
  4. MERHOD 方法声明
  5. PACKAGE 包声明
  6. PARAMETER 参数声明
  7. TYPE 类、接口(包括注释类型)或枚举声明

@Rentention

注解保留时间;

  1. RetentionPolicy.SOURCE 源代码
  2. RetentionPolicy.CLASS 默认 字节码
  3. RetentionPolicy.RUNTIME 运行时,一般是给反射使用

@Inherited

继承性说明
指定被修饰的Annotation将具有继承性, 如果某个类使用了某个注解,则其子类将自动被某个注解修饰

@Documented

文档类注解

自定义注解

@interface 注解名{
	访问修饰符 类型 成员名()[ default 默认值];
}

注解解析

package day21;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.lang.annotation.*;


@Target(ElementType.TYPE)// 范围
@Retention(RetentionPolicy.RUNTIME)// 什么时候
@Inherited // 继承
@Documented
@interface FuitAnno{
	// 只有一个成员时,用value作为方法名
	public String value() default "Apple";
	
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ColorAnno{
	public Color color() default Color.RED;
}

@FuitAnno(value="orange")
class Fuit{
	public String name;
	
}

enum Color{
	RED,GREEN,YELLOW;
}


class Apple extends Fuit{
	int size;
	// 颜色
	@ColorAnno(color = Color.YELLOW)
	Color colorName;
}

public class TestAnno {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		// 反射的技术  获得注解的信息
		// Fuit注解信息
		Class<?> c1 = Class.forName("day21.Fuit");
		Annotation[] ans = c1.getDeclaredAnnotations();
		Arrays.stream(ans).forEach(System.out::println);
		// Apple
		Class<?> c2 = Class.forName("day21.Apple");
		// 获得子类 继承父类的类型上的注解信息;
		Annotation[] ans1 = c2.getAnnotations();
		Arrays.stream(ans1).forEach(System.out::println);
		// 获得属性上的注解信息
		Annotation[] ans2 = c2.getDeclaredField("colorName").getAnnotations();
		Arrays.stream(ans2).forEach(System.out::println);
		
		
	}
}

posted @ 2018-10-03 00:59  耳_东  阅读(143)  评论(0)    收藏  举报