类加载器和反射有什么关系

2023-03-16 23:38 57次浏览 攻略

更多资源和微信公众号[Java帮助](不是微信朋友的公众号)和[Java帮助] QQ空间、技术文章、视频、面试资料。

欢迎关注!

学习交流请加【Java帮帮】自学交流QQ群553841695

1:反射(理解)

(1)类的加载及类加载器

类的加载:

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之创建一个Class对象。

任何类被使用时系统都会建立一个Class对象。

连接

验证 是否有正确的内部结构,并和其他类协调一致

准备 负责为类的静态成员分配内存,并设置默认初始化值

解析 将类的二进制数据中的符号引用替换为直接引用

初始化 就是我们以前讲过的初始化步骤

类初始化时机:

创建类的实例

访问类的静态变量,或者为静态变量赋值

调用类的静态方法

使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

初始化某个类的子类

直接使用java.exe命令来运行某个主类

类加载器:

负责将.class文件加载到内在中,并为之生成对应的Class对象。

虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

类加载器的组成

Bootstrap ClassLoader 根类加载器

Extension ClassLoader 扩展类加载器

Sysetm ClassLoader 系统类加载器

类加载器作用:

Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

Sysetm ClassLoader 系统类加载器

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

(2)反射:

通过字节码文件对象,去使用成员变量,构造方法,成员方法

package cn.itcast_01;

public class Person {

private String name;

int age;

public String address;

public Person() {

}

private Person(String name) {

= name;

}

Person(String name, int age) {

= name;

= age;

}

public Person(String name, int age, String address) {

= name;

= age;

= address;

}

public void show() {

Sy("show");

}

public void method(String s) {

Sy("method " + s);

}

public String getString(String s, int i) {

return s + "—" + i;

}

private void function() {

Sy("function");

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + ", address=" + address

+ "]";

}

}

package cn.itcast_01;

/*

* 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

*

* Person p = new Person();

* p.使用

*

* 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。

* Class类:

* 成员变量Field

* 构造方法Constructor

* 成员方法Method

*

* 获取class文件对象的方式:

* A:Object类的getClass()方法

* B:数据类型的静态属性class

* C:Class类中的静态方法

* public static Class forName(String className)

*

* 一般我们到底使用谁呢?

* A:自己玩任选一种,第二种比较方便

* B:开发第三种

* 为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。

*/

public class ReflectDemo {

public static void main(String[] args) throws ClassNotFoundException {

// 方式1

Person p = new Person();

Class c = p.getClass();

Person p2 = new Person();

Class c2 = ();

Sy(p == p2);// false

Sy(c == c2);// true

// 方式2

Class c3 = Per;

// int.class;

// S;

Sy(c == c3);

// 方式3

// ClassNotFoundException

Class c4 = Cla("cn.i;);

Sy(c == c4);

}

}

(3)反射的使用

A:通过反射获取构造方法并使用

package cn.itcast_02;(1)

import java.lang.re;

import cn.i;

/*

* 通过反射获取构造方法并使用。

*/

public class ReflectDemo {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Cla("cn.i;);

// 获取构造方法

// public Constructor[] getConstructors():所有公共构造方法

// public Constructor[] getDeclaredConstructors():所有构造方法

// Constructor[] cons = c.getDeclaredConstructors();

// for (Constructor con : cons) {

// Sy(con);

// }

// 获取单个构造方法

// public Constructor<T> getConstructor(Class<?>… parameterTypes)

// 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

Constructor con = c.getConstructor();// 返回的是构造方法对象

// Person p = new Person();

// Sy(p);

// public T newInstance(Object… initargs)

// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

Object obj = con.newInstance();

Sy(obj);

// Person p = (Person)obj;

// p.show();

}

}

package cn.itcast_02;(2)

import java.lang.re;

/*

* 需求:通过反射去获取该构造方法并使用:

* public Person(String name, int age, String address)

*

* Person p = new Person("林青霞",27,"北京");

* Sy(p);

*/

public class ReflectDemo2 {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Cla("cn.i;);

// 获取带参构造方法对象

// public Constructor<T> getConstructor(Class<?>… parameterTypes)

Constructor con = c.getConstructor(S, int.class,

S);

// 通过带参构造方法对象创建对象

// public T newInstance(Object… initargs)

Object obj = con.newInstance("林青霞", 27, "北京");

Sy(obj);

}

}

package cn.itcast_02;(3)

import java.lang.re;

/*

* 需求:通过反射获取私有构造方法并使用

* private Person(String name){}

*

* Person p = new Person("风清扬");

* Sy(p);

*/

public class ReflectDemo3 {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Cla("cn.i;);

// 获取私有构造方法对象

// NoSuchMethodException:每个这个方法异常

// 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。

Constructor con = c.getDeclaredConstructor(S);

// 用该私有构造方法创建对象

// IllegalAccessException:非法的访问异常。

// 暴力访问

con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。

Object obj = con.newInstance("风清扬");

Sy(obj);

}

}

B:通过反射获取成员变量并使用

package cn.itcast_03;

import java.lang.re;

import java.lang.re;

/*

* 通过发生获取成员变量并使用

*/

public class ReflectDemo {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Cla("cn.i;);

// 获取所有的成员变量

// Field[] fields = c.getFields();

// Field[] fields = c.getDeclaredFields();

// for (Field field : fields) {

// Sy(field);

// }

/*

* Person p = new Person(); p.address = "北京"; Sy(p);

*/

// 通过无参构造方法创建对象

Constructor con = c.getConstructor();

Object obj = con.newInstance();

Sy(obj);

// 获取单个的成员变量

// 获取address并对其赋值

Field addressField = c.getField("address");

// public void set(Object obj,Object value)

// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

addre(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"

Sy(obj);

// 获取name并对其赋值

// NoSuchFieldException

Field nameField = c.getDeclaredField("name");

// IllegalAccessException

nameField.setAccessible(true);

nameField.set(obj, "林青霞");

Sy(obj);

// 获取age并对其赋值

Field ageField = c.getDeclaredField("age");

ageField.setAccessible(true);

ageField.set(obj, 27);

Sy(obj);

}

}

C:通过反射获取成员方法并使用

package cn.itcast_04;

import java.lang.re;

import java.lang.re;

public class ReflectDemo {

public static void main(String[] args) throws Exception {

// 获取字节码文件对象

Class c = Cla("cn.i;);

// 获取所有的方法

// Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法

// Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法

// for (Method method : methods) {

// Sy(method);

// }

Constructor con = c.getConstructor();

Object obj = con.newInstance();

/*

* Person p = new Person(); p.show();

*/

// 获取单个方法并使用

// public void show()

// public Method getMethod(String name,Class<?>… parameterTypes)

// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型

Method m1 = c.getMethod("show");

// obj.m1(); // 错误

// public Object invoke(Object obj,Object… args)

// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数

m1.invoke(obj); // 调用obj对象的m1方法

Sy("———-");

// public void method(String s)

Method m2 = c.getMethod("method", S);

m2.invoke(obj, "hello");

Sy("———-");

// public String getString(String s, int i)

Method m3 = c.getMethod("getString", S, int.class);

Object objString = m3.invoke(obj, "hello", 100);

Sy(objString);

// String s = (String(obj, "hello",100);

// Sy(s);

Sy("———-");

// private void function()

Method m4 = c.getDeclaredMethod("function");

m4.setAccessible(true);

m4.invoke(obj);

}

}

(4)反射案例

A:通过反射运行配置文件的内容

B:通过反射越过泛型检查

C:通过反射给任意的一个对象的任意的属性赋值为指定的值

(5)动态代理

动态代理:

代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。

举例:春季回家买票让人代买

动态代理:在程序运行过程中产生的这个对象

而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib

Proxy类中的方法创建动态代理类对象

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

最终会调用InvocationHandler的方法

InvocationHandler

Object invoke(Object proxy,Method method,Object[] args)

2:设计模式

(1)装饰设计模式

装饰设计模式概述

装饰模式就是使用被装饰类的一个子类的实例,在客户端将这个子类的实例交给装饰类。是继承的替代方案

优点

使用装饰模式,可以提供比继承更灵活的扩展对象的功能,它可以动态的添加对象的功能,并且可以随意的组合这些功能

缺点

正因为可以随意组合,所以就可能出现一些不合理的逻辑

BufferedReader br = new BufferedReader(new InputStreamReader));

Scanner sc = new Scanner);

package cn.itcast_02;

public interface Phone {

public abstract void call();

}

package cn.itcast_02;

public class IPhone implements Phone {

@Override

public void call() {

Sy("手机可以打电话了");

}

}

package cn.itcast_02;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.u;

public class PhoneDemo {

public static void main(String[] args) {

Phone p = new IPhone();

p.call();

Sy("————");

// 需求:我想在接电话前,听彩铃

PhoneDecorate pd = new RingPhoneDecorate(p);

();

Sy("————");

// 需求:我想在接电话后,听音乐

pd = new MusicPhoneDecorate(p);

();

Sy("————");

// 需求:我要想手机在接前听彩铃,接后听音乐

// 自己提供装饰类,在打电话前听彩铃,打电话后听音乐

pd = new RingPhoneDecorate(new MusicPhoneDecorate(p));

();

Sy("———-");

// 想想我们在IO流中的使用

// InputStream is = Sy;

// InputStreamReader isr = new InputStreamReader(is);

// BufferedReader br = new BufferedReader(isr);

BufferedReader br = new BufferedReader(new InputStreamReader));

BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(

Sy)));

Scanner sc = new Scanner);

}

}

package cn.itcast_02;

public abstract class PhoneDecorate implements Phone {

private Phone p;

public PhoneDecorate(Phone p) {

= p;

}

@Override

public void call() {

.call();

}

}

package cn.itcast_02;

public class RingPhoneDecorate extends PhoneDecorate {

public RingPhoneDecorate(Phone p) {

super(p);

}

@Override

public void call() {

Sy("手机可以听彩铃");

();

}

}

package cn.itcast_02;

public class MusicPhoneDecorate extends PhoneDecorate {

public MusicPhoneDecorate(Phone p) {

super(p);

}

@Override

public void call() {

();

Sy("手机可以听音乐");

}

}

(2)模版设计模式

模版设计模式概述

模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现

优点

使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求

缺点

如果算法骨架有修改的话,则需要修改抽象类

package cn.itcast_01;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public abstract class GetTime {

// 需求:请给我计算出一段代码的运行时间

public long getTime() {

long start = Sy();

// for循环

// for (int x = 0; x < 10000; x++) {

// Sy(x);

// }

// 视频

// try {

// BufferedInputStream bis = new BufferedInputStream(

// new FileInputStream("a.avi"));

// BufferedOutputStream bos = new BufferedOutputStream(

// new FileOutputStream("b.avi"));

// byte[] bys = new byte[1024];

// int len = 0;

// while ((len = bis.read(bys)) != -1) {

// bos.write(bys, 0, len);

// }

// bos.close();

// bis.close();

// } catch (IOException e) {

// e.printStackTrace();

// }

// 再给我测试一个代码:集合操作的,多线程操作,常用API操作的等等…

code();

long end = Sy();

return end – start;

}

public abstract void code();

}

package cn.itcast_01;

public class GetTimeDemo {

public static void main(String[] args) {

// GetTime gt = new GetTime();

// Sy() + "毫秒");

GetTime gt = new ForDemo();

Sy() + "毫秒");

gt = new IODemo();

Sy() + "毫秒");

}

}

package cn.itcast_01;

public class ForDemo extends GetTime {

@Override

public void code() {

for (int x = 0; x < 100000; x++) {

Sy(x);

}

}

}

package cn.itcast_01;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class IODemo extends GetTime{

@Override

public void code() {

try {

BufferedInputStream bis = new BufferedInputStream(

new FileInputStream("a.avi"));

BufferedOutputStream bos = new BufferedOutputStream(

new FileOutputStream("b.avi"));

byte[] bys = new byte[1024];

int len = 0;

while ((len = bis.read(bys)) != -1) {

bos.write(bys, 0, len);

}

bos.close();

bis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

3:JDK新特性

(1)JDK5(掌握)

装箱和拆箱

泛型

增强for

静态导入

可变参数

枚举

枚举概述

是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。

回想单例设计模式:单例类是一个类只有一个实例

那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。

通过自己定义一个枚举类来演示案例

第一版

第二版

第三版

发现自己定义一个枚举类,比较麻烦,所以,java就提供了枚举类供我们使用。

格式是:只有枚举项的枚举类

public enum 枚举类名 {

枚举项1,枚举项2,枚举项3…;

}

int compareTo(E o)

String name()

int ordinal()

String toString()

<T> T valueOf(Class<T> type,String name)

values()

此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便

(2)JDK6(了解)

(3)JDK7(理解)

(1)二进制的表现形式:

JDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。使用二进制字面量的好处是,可以使代码更容易被理解。语法非常简单,只要在二进制数值前面加 0b或者0B

举例:

int x = ob110110

(2)用_分隔数据:

为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。

举例:

int x = 100_1000;

注意事项:

不能出现在进制标识和数值之间

不能出现在数值开头和结尾

不能出现在小数点旁边

(3)switch语句可是用字符串

switch 语句可以用字符串

(4)泛型推断(菱形泛型)

(5)多catch的使用

异常的多个catch合并

格式:

try(必须是java.lang.AutoCloseable的子类对象){…}

好处:

资源自动释放,不需要close()了

把需要关闭资源的部分都定义在这里就ok了

主要是流体系的对象是这个接口的子类(看JDK7的API)

(6)自动释放资源的用法

(4)JDK8(了解)

可以去网上了解资料


获取更多资源加微信公众号【Java帮帮】 (是公众号,不是微信好友哦)

还有【Java帮帮】QQ空间,技术文章,视频,面试资料。欢迎关注!

学习交流请加【Java帮帮】自学交流QQ群553841695

相关推荐