Java基础

1 类的加载,连接和初始化

         当我们调用Java命令来运行某个Java程序的时候,该命令会启动你一条Java虚拟机进程,不管该Java程序启动了多少个线程,他们都处于Java虚拟机进程里,他们都使用该Java进程的内存。

          当程序运行到最后正常结束,使用System.exit();或Runtime.getRuntime().exit();代码结束,或遇到未捕获异常或错误,或所在平台强制结束jvm进程。

          当程序使用某个类时,如果类还没有加载到内存,系统会通过加载,连接,初始化三个步骤对类 进行初始化。

          类的加载:类的加载是指将类的class文件读入内存,并为之创建一个java.lang.Class对象。类加载由类加载器完成,我们可以继承ClassLoader基类创建自己的类加载器

          类的二进制数据的来源:1 本地文件系统,2 jar包中的class文件,JDBC编程时用的驱动类,通过网络

         

           类的连接:把类的二进制数据合并到jre中,有验证(是否有错误),准备(为静态属性分内存)解析(符号引用变直接引用)

           初始化:虚拟机负责对类进行初始化,主要对静态属性初始化。Java中有两种方式对静态属性初始化,1声明时初始化 2,静态块初始化

          

class Shape{
	// 按顺序初始化
	static int a = 4; 
	static{
		a = 5;
	}
}

            当程序使用任何一个类时,会保证该类和其所有父类都初始化

            类初始化时机  1  创建类的事例,2 调用类静态方法,3 访问类静态属性,通过反射创建某个类的Class对象,初始化某个类的子类,直接使用java.exe运行某个类

            对于一个final型静态属性,如果在编译时就得到值,就把该属性称为编译时常量,当使用编译时常量时,系统认为类是被动使用的,不会对类初始化

             

class Shape{
	// 使用变量a不会导致类初始化
	static int a = 4; 
	//使用变量b,会导致类初始化
	static int b = new Random().nextInt();
}
              类加载器 : 负责将.class文件加载到内存,并生成Class对像,jvn中,类的全限定名和其类加载器作为类的唯一标识,类加载器分为3类。

             1 根类加载器,负责加载核心类(system,String类),没有继承ClassLoad类

              2 扩展类加载器 加载jre扩展目录中的jar包 D:\program\1.7\jre\lib\ext 目录下

              3 系统类加载器  classpath环境变量的包和类路径

              类加载机制:1全盘负责:当加载某个类时,类所依赖和引用的类全部由一个类加载器加载,2 父类委托,父类不能加载,子类才加载,3 缓存机制

               获取Class对象的三种方式

                1: Class.forName() 静态方法,参数为类的全限定名2 : 调用类的class属性    3 : 调用对象的getClasss()方法

                一旦获取了类所对应的class对像,就可以调用class对像的方法获取对象和类的真实信息了。 Class类提供大量实例方法获取class对象所对应类的详细信息,包含如下几类方法。

                1:访问类所包含的构造器   2:访问类所包含的方法 3 : 访问类包含的方法 4 : 访问类上包含的注视 5 包含的内部类, 6 外部类 7 所继承的类,接口,类的修饰符

                

public class MyTest {
	public static void main(String[] args) {
		Class<ClassTest> clazz = ClassTest.class;
		Constructor[] ctors = clazz.getDeclaredConstructors();
		System.out.println("全部构造器");
		for (Constructor c : ctors){
			System.out.println(c);
		}
		Constructor[] pctors = clazz.getConstructors();
		System.out.println("全部public构造器");
		for (Constructor c : pctors){
			System.out.println(c);
		}
	}
}

@SuppressWarnings(value="uncheked")
@Deprecated
class ClassTest{

	private ClassTest(){}
	
	public ClassTest(String name){
		System.out.println("有参构造器");
	}
	
	public void info(){
		System.out.println("无参info");
	}
	
	public void info(String str) {
		System.out.println("有参info" + str);
	}
	
	class Inner{
		
	}
}
             使用反射生成并操作对象

              Class 对象可以类里的成分包括方法(有Method对象表示),构造器(由Constructor对象表示),Field(由Field对象表示),三个类在Java.lang.reflect包下,并实现了java.lang.reflect.Member接口,程序可以通过Method对象执行对应方法,通过Constructor对象调用构造器创建对象,通过Field对像访问并修该对象属性值

              1 创建对像 

                利用反射创建对象有两种方式,1 如果类有默认构造器,用Class对象的newInstance()方法创建实例。2 先用Class对象获取指定的Constructor对象,在调用Constructor的newInstance()方法创建实例。

           

public class MyTest {
	public static void main(String[] args) throws Exception {
		Class<ClassTest> clazz = ClassTest.class;
		//默认构造器创建事例
		ClassTest c1 = clazz.newInstance();
		System.out.println(c1);
		// 有参构造器创建事例
		Constructor<ClassTest> con = clazz.getConstructor(String.class);
		ClassTest c2 = con.newInstance("ba");
		System.out.println(c2);
	}
}

class ClassTest{
	private String name = "hello";
	
	public ClassTest() {
		// TODO Auto-generated constructor stub
	}
	public ClassTest(String name){
		this.name = name;
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name;
	}
}
            调用方法,Method类中invoke() 方法可以,
     
public class MyTest {
	public static void main(String[] args) throws Exception {
		Class<ClassTest> clazz = ClassTest.class;
		//默认构造器创建事例
		ClassTest c1 = clazz.newInstance();
		System.out.println(c1);
		Method m = clazz.getMethod("setName", String.class);
		//不检测访问权限
		m.setAccessible(true);
		m.invoke(c1, "ab"); //调用方法
		System.out.println(c1);
	}
}

class ClassTest{
	private String name = "hello";
	
	public ClassTest() {
		// TODO Auto-generated constructor stub
	}
	public ClassTest(String name){
		this.name = name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name;
	}
}
                  访问属性值: getXX()    setXX()

     

public class MyTest {
	public static void main(String[] args) throws Exception {
		Class<ClassTest> clazz = ClassTest.class;
		//默认构造器创建事例
		ClassTest c1 = clazz.newInstance();
		System.out.println(c1);
		Field f = clazz.getDeclaredField("name");
		f.setAccessible(true);
		f.set(c1, "fd");
		System.out.println(c1);
	}
}

class ClassTest{
	private String name = "hello";
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return name;
	}
}
                  m3就是将要传入的method,所以,为什么先输出before,后输出after,到这里是不是全明白了呢?这,就是JDK的动态代理整个过程,不难吧?

最后,我稍微总结一下JDK动态代理的操作过程:

1. 定义一个接口,该接口里有需要实现的方法,并且编写实际的实现类。

2. 定义一个InvocationHandler类,实现InvocationHandler接口,重写invoke()方法,且添加getProxy()方法。

总结一下动态代理实现过程:

1. 通过getProxyClass0()生成代理类。

2. 通过Proxy.newProxyInstance()生成代理类的实例对象,创建对象时传入InvocationHandler类型的实例。

3. 调用新实例的方法,即此例中的add(),即原InvocationHandler类中的invoke()方法。

public class MyTest {
	public static void main(String[] args) throws Exception {
		final Student s = new Student();
		Do s1 = (Do) Proxy.newProxyInstance(MyTest.class.getClassLoader(), s.getClass().getInterfaces(), 
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						System.out.println("before");
						Object c =  method.invoke(s, args);
						System.out.println("after");
						return c;
					}
				});
		s1.dosome();
	}
}
interface Do{
	void dosome();
}
class Student implements Do{

	@Override
	public void dosome() {
		// TODO Auto-generated method stub
		System.out.println("study");
	}
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值