day13
缓冲字节流
之前学的是基于硬盘的。
缓冲字节输出流
缓冲流实现文件的复制
每次读取到的数据的长度
缓冲字符流
输出流
copy
处理流之一:缓冲流
转换流
处理流之二:转换流
转换字节输入流为字符输入流
转换字节输出流为字符输出流
调用:类名.方法
标准输入输出流
处理流之三:标准输入输出流
标准的输入流
练习
写静态方法是为了方便,因为可以类名.方法名调用,不用new对象。
调用:
打印流(了解)和数据流(了解)
打印流
数据流
数据输出流
数据输入流
对象流
序列化与反序列化针对的是对象的各种属性,不包括类的属性。
(问题?对象的各种属性不就是类的属性吗?
类属性:static修饰的,通过类名.属性获取。
对象属性:get、set调用的,通过对象.属性获取。)
对象的序列化
举例
Person.java
序列化与反序列化
调用
注意
因为不在一个包内:反序列化报错!!!
随机存取流-RandomAccessFile类
RandomAccessFile类
随机读文件
随机写文件
调用:
流的基本应用小结
流是用来处理数据的。
处理数据时,一定要先明确数据源,与数据目的地。
- 数据源可以是文件,可以是键盘。
- 数据目的地可以是文件、显示器或者其他设备。
而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。
day14
反射
本章主要内容
- 理解Class类并实例化Class类对象;
- 运行时创建类对象并获取类的完整结构;
- 通过反射调用类的指定方法、指定属性;
- 动态代理
人类的反射过程,看见葫芦娃3个字。
JAVA Refection:反射是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的成员变量和方法;
- 生成动态代理。
比如你通过AOP给每个类添加入参出参日志。你需要打印类名、方法名、入参、出参等信息。这些信息,都是通过反射获取的。
Class类
即:可以通过对象反射求出类的名称。
在Object类中定义了以下的方法,此方法就将被所有子类继承:
public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
反射可以得到的信息:某个类的属性、方法和构造方法、某个类到底实现类哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。
- Class本身也是一个类;
- Class对象只能有系统建立对象;
- 一个类在JVM中只会有一个Class实例;
- 每个类的实例都会记得自己是由哪个Class实例所生成;
- 通过Class可以完整地得到一个类中的完整结构。
package course05;
import course02.Person;
public class Test {
public static void main(String[] args) {
Person p = new Person();
//clazz对象中就包含对象p所属的Person类的所有的信息
Class clazz = p.getClass();
System.out.println(clazz);
//class course02.Person
}
}
package course02;
public class Person {
int age;
String name;
int sex;
public void showInfo(){
System.out.println(this.age);
System.out.println(this.name);
System.out.println(this.sex);
}
// public void setInfo(int age, String name, int sex){
// this.age = age;
// this.name = name;
// this.sex = sex;
// }
}
实例化class类对象
package course05;
import course02.Person;
public class Test {
public static void main(String[] args) {
Person p = new Person();
//clazz对象中就包含对象p所属的Person类的所有的信息
Class clazz = p.getClass();
System.out.println("clazz: " + clazz);
//class course02.Person
//通过类名.class创建指定类的Class实例
Class c0 = Person.class;
//通过一个类的实例对象的getClass()方法,获取对应实例对象的类的Class实例。
Class c1 = p.getClass();
try {
//通过Class的静态方法forName(String className)来获取一个类的Class实例
// forName(String className)方法中的参数是你要获取的Class实例的类的全路径(包名.类名)
Class c2 = Class.forName("course02.Person");
System.out.println("c2: " + c2);
}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}
//clazz: class course02.Person
//c2: class course02.Person
反射获取一个类的父类和接口
Field、Method、Constructor、Superclass、Interface、Annotation
- 实现的全部接口
- 所继承的父类
- 全部的构造方法
- 全部的方法
- 全部的Field
反射获取一个类的构造方法
举例:
接口
package basic05;
public interface Study {
void studyInfo();
}
package basic05;
public interface Move {
void moveType();
}
父类
package basic05;
public class Person {
public String name;
int age;
}
类&调用
package basic05;
import java.lang.reflect.Constructor;
public class Student extends Person implements Move, Study{
String school;
public Student(){
}
//main方法里,可以获取公有构造方法
public Student(String school){
this.school = school;
}
private Student(String name, int age){
this.name = name;
this.age = age;
}
public void showInfo(){
System.out.println("学校是:" + this.school);
}
@Override
public void moveType() {
System.out.println("骑自行车上学");
}
@Override
public void studyInfo() {
System.out.println("学习的中学的知识");
}
public static void main(String[] args) {
try{
//通过包名.类名的字符串,调用Class.forName方法获取指定类
//clazz类的Class实例
Class clazz = Class.forName("basic05.Student");
Class superClazz = clazz.getSuperclass(); //获取父类
System.out.println("获取父类:" + superClazz.getName());
//获取当前类的所有接口
Class[] interfaces = clazz.getInterfaces();
for (Class c: interfaces
) {
System.out.println("接口:" + c.getName());
}
//获取构造方法
//获取类的公有构造方法
Constructor[] cons = clazz.getConstructors();
for (Constructor c: cons
) {
System.out.println("公有构造方法名称:" + c.getName());
//getModifiers取得方法的修饰符,返回数组1代表public
System.out.println("公有构造方法名称:" + c.getName() + "的修饰符是:" + c.getModifiers());
Class[] paramClazz = c.getParameterTypes();
for (Class pc: paramClazz
) {
System.out.println("公有构造方法名称:" + pc.getName() + "的参数类型是:" + pc.getName());
}
}
//获取类的所有构造方法,包括公有和私有的
Constructor[] cons1 = clazz.getDeclaredConstructors();
for (Constructor c: cons1
) {
System.out.println("-------------------------");
System.out.println("构造方法名称:" + c.getName());
//1为public,2为private
System.out.println("构造方法名称:" + c.getName() + "的修饰符是:" + c.getModifiers());
//获取构造方法的参数类型,有几个参数数组的元素就有几个
Class[] paramClazz = c.getParameterTypes();
for (Class pc: paramClazz
) {
System.out.println("构造方法名称:" + pc.getName() + "的参数类型是:" + pc.getName());
}
System.out.println("--------------------------------");
}
} catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}
/*
获取父类:basic05.Person
接口:basic05.Move
接口:basic05.Study
公有构造方法名称:basic05.Student
公有构造方法名称:basic05.Student的修饰符是:1
公有构造方法名称:java.lang.String的参数类型是:java.lang.String
公有构造方法名称:basic05.Student
公有构造方法名称:basic05.Student的修饰符是:1
-------------------------
构造方法名称:basic05.Student
构造方法名称:basic05.Student的修饰符是:2
构造方法名称:java.lang.String的参数类型是:java.lang.String
构造方法名称:int的参数类型是:int
--------------------------------
-------------------------
构造方法名称:basic05.Student
构造方法名称:basic05.Student的修饰符是:1
构造方法名称:java.lang.String的参数类型是:java.lang.String
--------------------------------
-------------------------
构造方法名称:basic05.Student
构造方法名称:basic05.Student的修饰符是:1
--------------------------------
Process finished with exit code 0
*/
通过反射创建一个对象
调用构造方法能干什么呢?
package basic05;
import java.lang.reflect.Constructor;
public class Student2 extends Person implements Study, Move{
String school;
public Student2(){
System.out.println("调用的是public Student()");
}
//main方法里,可以获取公有构造方法
public Student2(String school){
this.school = school;
System.out.println("调用的是public Student2(String school)");
}
private Student2(String name, int age){
this.name = name;
this.age = age;
System.out.println("调用的是private Student2(String name, int age)");
}
public void showInfo(){
System.out.println("学校是:" + this.school);
}
@Override
public void moveType() {
System.out.println("骑自行车上学");
}
@Override
public void studyInfo() {
System.out.println("学习的中学的知识");
}
public static void main(String[] args) {
try {
//clazz类的Class实例
Class clazz = Class.forName("basic05.Student2");
//如果用反射的构造方法来创建对象
// Object obj = clazz.newInstance(); //相当于调用Student类的无参公有构造方法
// Student2 stu = (Student2) obj;
//指定获取有一个参数并且为String类型的公有构造方法
Constructor c = clazz.getConstructor(String.class);
//newInstance实例化对象,相当于调用public Student2(String school);
Student2 stu1 = (Student2)c.newInstance("第一中学");
System.out.println("stu1:" + stu1.school);
System.out.println("--------------------------------------");
//通过反射机制,可以强制的调用私有的构造方法
//获取有两个参数的构造方法
Constructor c1 = clazz.getDeclaredConstructor(String.class, int.class);
//接触私有的封装,下面就可以对这个私有方法强制调用
Student2 stu = (Student2)c1.newInstance("zhangsan", 12);
System.out.println("stu:" + stu.name + "+" + stu.age);
}catch (Exception e){
e.printStackTrace();
}
}
}
/*
调用的是public Student2(String school)
stu1:第一中学
--------------------------------------
调用的是private Student2(String name, int age)
stu:zhangsan+12
*/
反射机制获取类的方法
student新增方法
main方法里
反射机制获取类的属性和包
student新增属性
属性
包
反射机制调用指定方法
stuent新增方法
main里指定调用
调用重载方法
和有返回值的方法
main调用 ...是0到多个的意思
第一中学是这里来的
反射机制调用指定属性
共有的属性
私有的属性
java动态代理(反射的关键应用)
Proxy:专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
先要做个接口
package basic05.ProxyDemo;
public interface ITestDemo {
void test1();
void test2();
}
实现类
main里
被代理的对象是test,返回object,是成功被代理后的对象。
动态代理类
动态代理步骤
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作;
- 创建被代理的类以及接口;
- 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理;
- 通过Subject代理调用RealSubject实现类的方法。