0
点赞
收藏
分享

微信扫一扫

27.反射,类加载器,设计模式,jdk新特性


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) {

this.name = name;

}


Person(String name, int age) {

this.name = name;

this.age = age;

}


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

this.name = name;

this.age = age;

this.address = address;

}


public void show() {

System.out.println("show");

}


public void method(String s) {

System.out.println("method " + s);

}


public String getString(String s, int i) {

return s + "---" + i;

}


private void function() {

System.out.println("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 = p2.getClass();


System.out.println(p == p2);// false

System.out.println(c == c2);// true


// 方式2

Class c3 = Person.class;

// int.class;

// String.class;

System.out.println(c == c3);


// 方式3

// ClassNotFoundException

Class c4 = Class.forName("cn.itcast_01.Person");

System.out.println(c == c4);

}

}


(3)反射的使用

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


package cn.itcast_02;(1)


import java.lang.reflect.Constructor;


import cn.itcast_01.Person;


/*

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

 */

public class ReflectDemo {

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

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");


// 获取构造方法

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

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

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

// for (Constructor con : cons) {

// System.out.println(con);

// }


// 获取单个构造方法

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

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

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


// Person p = new Person();

// System.out.println(p);

// public T newInstance(Object... initargs)

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

Object obj = con.newInstance();

System.out.println(obj);


// Person p = (Person)obj;

// p.show();

}

}


package cn.itcast_02;(2)


import java.lang.reflect.Constructor;


/*

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

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

 * 

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

 * System.out.println(p);

 */

public class ReflectDemo2 {

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

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");


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

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

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

String.class);


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

// public T newInstance(Object... initargs)

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


System.out.println(obj);

}

}


package cn.itcast_02;(3)


import java.lang.reflect.Constructor;


/*

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

 * private Person(String name){}

 * 

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

 * System.out.println(p);

 */

public class ReflectDemo3 {

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

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");


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

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

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

Constructor con = c.getDeclaredConstructor(String.class);


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

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

// 暴力访问

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

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


System.out.println(obj);

}

}


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


package cn.itcast_03;


import java.lang.reflect.Constructor;

import java.lang.reflect.Field;


/*

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

 */

public class ReflectDemo {

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

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");


// 获取所有的成员变量

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

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

// for (Field field : fields) {

// System.out.println(field);

// }


/*

* Person p = new Person(); p.address = "北京"; System.out.println(p);

*/


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

Constructor con = c.getConstructor();

Object obj = con.newInstance();

System.out.println(obj);


// 获取单个的成员变量

// 获取address并对其赋值

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

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

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

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

System.out.println(obj);


// 获取name并对其赋值

// NoSuchFieldException

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

// IllegalAccessException

nameField.setAccessible(true);

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

System.out.println(obj);


// 获取age并对其赋值

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

ageField.setAccessible(true);

ageField.set(obj, 27);

System.out.println(obj);

}

}


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


package cn.itcast_04;


import java.lang.reflect.Constructor;

import java.lang.reflect.Method;


public class ReflectDemo {

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

// 获取字节码文件对象

Class c = Class.forName("cn.itcast_01.Person");


// 获取所有的方法

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

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

// for (Method method : methods) {

// System.out.println(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方法


System.out.println("----------");

// public void method(String s)

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

m2.invoke(obj, "hello");

System.out.println("----------");


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

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

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

System.out.println(objString);

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

// System.out.println(s);

System.out.println("----------");


// 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(System.in));


Scanner sc = new Scanner(System.in);


package cn.itcast_02;


public interface Phone {

public abstract void call();

}


package cn.itcast_02;


public class IPhone implements Phone {


@Override

public void call() {

System.out.println("手机可以打电话了");

}


}


package cn.itcast_02;


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.util.Scanner;


public class PhoneDemo {

public static void main(String[] args) {

Phone p = new IPhone();

p.call();

System.out.println("------------");


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

PhoneDecorate pd = new RingPhoneDecorate(p);

pd.call();

System.out.println("------------");


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

pd = new MusicPhoneDecorate(p);

pd.call();

System.out.println("------------");


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

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

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

pd.call();

System.out.println("----------");

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

// InputStream is = System.in;

// InputStreamReader isr = new InputStreamReader(is);

// BufferedReader br = new BufferedReader(isr);

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(

System.out)));


Scanner sc = new Scanner(System.in);

}

}


package cn.itcast_02;


public abstract class PhoneDecorate implements Phone {


private Phone p;


public PhoneDecorate(Phone p) {

this.p = p;

}


@Override

public void call() {

this.p.call();

}

}


package cn.itcast_02;


public class RingPhoneDecorate extends PhoneDecorate {


public RingPhoneDecorate(Phone p) {

super(p);

}


@Override

public void call() {

System.out.println("手机可以听彩铃");

super.call();

}

}


package cn.itcast_02;


public class MusicPhoneDecorate extends PhoneDecorate {


public MusicPhoneDecorate(Phone p) {

super(p);

}


@Override

public void call() {

super.call();

System.out.println("手机可以听音乐");

}

}


(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 = System.currentTimeMillis();

// for循环

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

// System.out.println(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 = System.currentTimeMillis();


return end - start;

}


public abstract void code();

}


package cn.itcast_01;


public class GetTimeDemo {

public static void main(String[] args) {

// GetTime gt = new GetTime();

// System.out.println(gt.getTime() + "毫秒");


GetTime gt = new ForDemo();

System.out.println(gt.getTime() + "毫秒");


gt = new IODemo();

System.out.println(gt.getTime() + "毫秒");

}

}


package cn.itcast_01;


public class ForDemo extends GetTime {


@Override

public void code() {

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

System.out.println(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帮帮”今日头条号,技术文章与新闻,每日更新,欢迎阅读

学习交流请加Java帮帮交流QQ群553841695

分享是一种美德,分享更快乐!

27.反射,类加载器,设计模式,jdk新特性_类加载器



举报

相关推荐

0 条评论