Java高级语言笔记(3)
2.5反射机制
Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息类创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展。
- 创建student类(以下代码的student类都是基于此)
package com.kg.test;
/**
* @author ZRB
* @description
* @date 2023/8/28 14:57
*/
public class Student {
private String no ;
String name;
protected String sex;
public int age;
public Student(){
}
private Student(String no){
this.no = no;
}
public Student(String no, String name, String sex, int age) {
this.no = no;
this.name = name;
this.sex = sex;
this.age = age;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void sayHi(){
System.out.println(String.format("您好!我叫%s,今年%s岁,性别是%s,学号为%s",getName(),getAge(),getSex(),getNo()));
}
public void study(int time){
System.out.println("我是"+this.getName()+",我每天学习"+time);
}
}
- 创建测试类Test01
package com.kg.test;
/**
* @author ZRB
* @description: 获取Class类的对象:我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型 ** 的对象
* @date 2023/8/28 15:23
*/
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException {
//获取类型的的class对象,就是该类型的字节码文件对象。通过该对象,可以在程序运行的过程中动态创建对象,动态操作对象的原因
//获取字节码对象:方法一,通过类型、class属性获取
Class<Student> stuclass1 = Student.class;
System.out.println(stuclass1);
//方法二:通过getClass()方法获取
Class<? extends Student> stuclass2 = new Student().getClass();
System.out.println(stuclass2);
//方式三:通过Class.forName方法。指定类的完整名获取。注意:类的完整名是”包名、类名“
Class<?> stuclass3 = Class.forName("com.kg.test.Student");
System.out.println(stuclass3);
/*
注意:上面的代码跟下面的代码,一定要区分开,上面的代码返回的是stundent类型的字节码文件对象,下面的代码直接创建一个stundent类型对象
*/
Student student = new Student();
System.out.println(student);
/*
其实在我们创建一个studnet对象时,java虚拟机也是通过student类型的class对象,去创建student对象的
反射机制,只是这种被动方式,改成主动的方式
*/
}
}
2.5.1反射获取构造方法并使用
Class类中用于获取构造方法的方法
- Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
- Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
- Constructor getConstructor(Class<?>…parameterTypes):返回单个公共构造方法对象
- Constructor getDeclaredConstructor(Class<?>…parameterTypes):返回单个构造方法对象
Constructor类中用于创建对象的方法
- T newInstance(Object…initargs):根据指定的构造方法创建对象
- public void setAccessible(boolean flag):值为true,取消访问检查
Class<?> c = Class.forName("test.Student");
// 获取公共的构造方法
// Constructor<?>[] cons = c.getConstructors();
// 获取所有构造方法
Constructor<?>[] cons = c.getDeclaredConstructors();
for(Constructor con : cons){
System.out.println(con)
}
// 获取构造方法对象
Constructor<?> con = c.getConstructor();
// 创建对象实例
Object obj = con.newInstance();
System.out.println(obj);
// 获取Class对象
Class<?> c = Class.forName("test.Student");
// 基本数据类型也可以通过.class得到对应的Class类型
Constructor<?> con = c.getConstructor(String.class,int.class,String.class);
Object obj = con.newInstance("张三",20,"北京");
System.out.println(obj);
// 获取Class对象
Class<?> c = Class.forName("test.Student");
// 基本数据类型也可以通过.class得到对应的Class类型
Constructor<?> con = c.getConstructor(String.class);
// 暴力反射
con.setAccessible(true);
Object obj = con.newInstance("张三");
System.out.println(obj);
2.5.2返回获取成员变量并使用
Class类中用于获取成员变量的方法
- Field[] getFields():返回所有公共成员变量对象的数组
- Field[] getDeclaredFields():返回所有成员变量对象数组
- Field getField(String name):返回单个公共成员变量对象
- Field getDeclaredField(String name):返回单个成员变量对象
Field类中用于给成员变量赋值的方法
- void set(Object obj,Object value):给obj对象的成员变量赋值为value
// 获取Class对象
Class<?> c = Class.forName("test.Student");
// 获取公共成员变量
// Field[] fields = c.getFields();
// 获取成员变量
Field[] fields = c.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
// Field addressField = c.getField("address");
Field addressField = c.getDeclaredField("address");
// 获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
// 给obj对象的成员变量addressField赋值北京
addressField.set(obj,"北京");
System.out.println(obj);
2.5.3 反射获取成员方法并使用
Class类中用于获取成员方法的方法
- Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
- Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
- Method getMethod(String name,Class<?>…parameterTypes):返回单个公共成员方法对象
- Method getDeclaredMethod(String name,Class<?>…parameterTypes):返回单个成员方法对象
Method类中用于调用成员方法的方法
- Object invoke(Object obj,Object…args):调用obj对象的成员方法,参数是args,返回值是Object类型
package com.kg.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author ZRB
* @description:使用反射获取成员方法并使用
* @date 2023/8/29 8:37
*/
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取Student类型的class对象
Class<?> studentClass = Class.forName("com.kg.test.Student");
//getMethods方法:获取所有的公共方法,包括自己的所有公共方法和继承的方法
Method[] methods = studentClass.getMethods();
System.out.println("公共方法:");
for (Method m:methods) {
System.out.println(m);
}
//getDeclaredMethods方法:获取所有的方法,只包含自己的所有方法
Method[] declaredMethods = studentClass.getDeclaredMethods();
System.out.println("所有方法:");
for (Method method:declaredMethods){
System.out.println(method);
}
System.out.println("-----------------------------------------");
//获取单个公共方法(可以获取自己的也可以获取继承的)
Method setNo = studentClass.getMethod("setNo", String.class);
System.out.println(setNo);
Method study = studentClass.getMethod("study", int.class);
System.out.println(study);
//获取单个方法(可以获取私有的也可以获取公共的,但是获取不到继承的)
Method sayHi = studentClass.getDeclaredMethod("sayHi");
System.out.println(sayHi);
//执行获取到的方法
System.out.println(" 1.得到构造函数对象");
Constructor<?> constructor = studentClass.getConstructor();
System.out.println("2.创建实例对象");
Object o =constructor.newInstance();
System.out.println("3.执行对象身上的指定方法");
setNo.invoke(o,"张三");
study.invoke(o,5);
//注意:sayhi是私有方法
sayHi.setAccessible(true);
sayHi.invoke(o);
}
}
2.5.4 使用反射向集合中添加字符串
package com.kg.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* @author ZRB
* @description:向int集合中添加字符串
* @date 2023/8/29 9:34
*/
public class Test01 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> list = new ArrayList<Integer>();
//使用反射技术,得到list对象类型的class对象
Class<? extends ArrayList> aClass = list.getClass();
//根据arraylist对象类型的class对象,反射得到它的add方法对象
Method add = aClass.getMethod("add", Object.class);
//执行list对象的add方法,添加成员
list.add(100);//使用正常手法给集合对象添加成员
list.add(200);
add.invoke(list,"hello");//使用反射手法给对象添加成员
add.invoke(list,"word");
/*
根据上面的代码,可以给发现使用反射技术能向int集合中添加字符串成员
说明,泛型集合,只是jdk表层的一种封装,集合的底层类型依然是Object
*/
System.out.println(list);
}
}
2.6 XML( EXtensible Markup Language)
XML概述
- XML的全称为(EXtensible Markup Language),是一种可扩展的标记语言
- 标记语言:通过标签来描述数据的一门语言(标签有时我们也将其称为元素)
- 可扩展:标签的名字是可以自己定义的
- 语法规则一:
语法规则 | 示例代码 |
---|---|
是由一对尖括号和一组合法标识符组成 | |
在xml标签往往是成对出现,有开始也有结束 | |
在xml有一些特殊的标签也可以不成对出现,但是必须要存在结束标记 | |
在xml中标签可以定义属性,但是属性必须通过引号引起来 | |
标签可以进行正确嵌套 | zhangsan |
- 语法规则二:
语法规则 | 示例代码 |
---|---|
xml文件的后缀名普遍都是xml | user.xml,students.xml |
xml要有文档声明,文档声明必须是第一行第一列 | <?xml version="1.0" encoding="utf-8"?> |
xml必须要存在一个根标签,并且有且仅有一个 | |
xml文件中可以定义注释信息 | |
xml文件中可以存在以下特殊字符 | <;>; |
xml文件中可以存在CDATA区(写特殊字符) | <![CDATA[a\ |
- 创建student.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--xml文件头部必须存在<?xml version="1.0" encoding="UTF-8" ?>-->
<students>
<student no="1001">
<name>张三</name>
<age>22</age>
<sex>男</sex>
<score value="99"/>
</student>
<student no="1002">
<name>李四</name>
<age>26</age>
<sex>男</sex>
<score value="66"/>
</student>
<student no="1002">
<name>王五</name>
<age>18</age>
<sex>男</sex>
<score value="19"/>
</student>
</students>
<!--
xml是可扩展标记语言:表示标签和标签属性都是可自由扩展的,xml文件的作用是根据自定义格式保存数据
<?xml version="1.0" encoding="UTF-8" ?>
是xml文件声明,必须放置在第一行,文档声明中必须要定义version属性,表示版本,通常还会设置encodin="UTF-8",指定编码格式
每个xml文件必须要有一个根节点,并且只有一个根节点,xml文件通过节点的文本和节点的属性保存数据
xml中的节点必须要成对出现,单标签必须要自闭和,否则就报错
-->
2.6.1解析xml文件
- 创建解析类Test(解析上面student.xml文件)
package com.kg.xml;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.time.format.SignStyle;
import java.util.List;
/**
* @author ZRB
* @description:解析xml文件
* @date 2023/8/29 14:53
*/
public class Test {
public static void main(String[] args) throws FileNotFoundException, DocumentException {
//创建一个xml文件解析器
SAXReader reader =new SAXReader();
//获取document对象(可以理解为要解析的整个xml文件对象)
Document document = reader.read(new FileInputStream("Chapter07\\src\\com\\kg\\xml\\student.xml"));
//获取xml文档对象的根节点
Element root =document.getRootElement();
//获取指定节点名称的所有子节点
List<Element> student = root.elements("student");
System.out.println("学号\t\t姓名\t\t性别\t\t年龄\t\t成绩");
for (Element element :student) {
//获取当前节点的no属性的值
String no = element.attribute("no").getValue();
//获取当前节点的子节点的文本值
String name = element.element("name").getText();
String age = element.element("age").getText();
String sex = element.element("sex").getText();
//获取当前节点的score子节点的value属性值
String score = element.element("score").attribute("value").getValue();
System.out.println(no+"\t"+name+"\t\t"+sex+"\t\t"+age+"\t\t"+score);
}
}
}
2.6.2解析上面 student.xml 并把数据放在集合中
- 创建student类
package com.kg.xml;
/**
* @author ZRB
* @description
* @date 2023/8/29 15:53
*/
public class Student {
private String no;
private String name;
private int age;
private String sex;
private double score;
public Student() {
}
public Student(String no, String name, int age, String sex, double score) {
this.no = no;
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", score=" + score +
'}';
}
}
- 创建test类然后放入数据(原则:先解析再放入)
package com.kg.xml;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
/**
* @author ZRB
* @description
* @date 2023/8/29 15:56
*/
public class Test01 {
public static void main(String[] args) throws FileNotFoundException, DocumentException {
//创建一个学生集合
List<Student> students = new ArrayList<Student>();
//解析一个xml文件,并将数据添加到该集合中
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream("Chapter07\\src\\com\\kg\\xml\\student.xml"));
//获取xml文档对象的根节点
Element root =document.getRootElement();
//获取指定节点名称的所有子节点
List<Element> student = root.elements("student");
for (Element element :student) {
Student student1 =new Student();
//获取当前节点的no属性的值
String no = element.attribute("no").getValue();
//获取当前节点的子节点的文本值
String name = element.element("name").getText();
String age = element.element("age").getText();
String sex = element.element("sex").getText();
//获取当前节点的score子节点的value属性值
String score = element.element("score").attribute("value").getValue();
student1.setNo(no);
student1.setName(name);
student1.setAge(Integer.parseInt(age));
student1.setSex(sex);
student1.setScore(Double.parseDouble(score));
students.add(student1);
}
//遍历集合
for (Student s:students) {
System.out.println(s);
}
}
}