【零基础 快速学Java】韩顺平 零基础30天学会Java

## 1. Properties
### 1.1 Properties类
#### 1.1.1 需求的引出
com.wjedu.properties_ Properties.01.java
如下一个配置文件 My_Sql.properties
```xml
ip=192.168.0.13
user=root
pwd=12345
```
编程读取,ip user pwd的值,一般这个配置文件是给客户使用的。
分析
1.传统的方式
```java
BufferedReader bf =new BufferedReader(new FileReader("src\\My_Sql.properties"));
String line= ""
while((line = br.readLine())!=null){//循环读取
System.out.print(line);
Sprint[] split = line.sprint("=")//传统方式比较麻烦
System.out.print(split[0]);
System.out.print(split[1]);
System.out.print(split[2]);
}
```
2.Properties类可以方便实现
#### 1.1.2 Properties类基本介绍

1)专门用于读写配置文件的集合类
配置文件格式:键=值
2)注意:键值不能需要又空格,值不需要引号一起来,默认类型是String
#### 1.1.3 Properties类的常用方法
- load:加载配置文件的键值对到Properties对象
- list:将数据显示到指定设备
- getProperties(key):根据键获取值
- setProperties(key,value):设置简直对到properties对象
- store:讲Properties中的简直对存储到配置文件中,再idea中,保存信息到配置文件,如果含有中文,存储为unicode码。
```java
import java.io.IOException;
import java.util.Properties;
public class Properties01 {
public static void main(String[] args) throws IOException {
// 获取Porperties对象
Properties properties = new Properties();
// 加载指定文件
properties.load(new FileReader("src\\mysql.properties"));
// 把k-v显示控制到控制台
properties.list(System.out);
// 取得对应的键的值
String user = (String) properties.get("user");
String user1 = properties.getProperty("user");
String pwd = (String) properties.get("pwd");
System.out.println(user);
System.out.println(user1);
System.out.println(pwd);
}
}
```
## 2.反射(reflection)
### 2.1 需求的引出
根据配置文件re.properties 指定信息,创建Cat对象,并调用hi()方法
```xml
classfullpath=com.wjedu.Cat
method=hi
```
```java
package com.wjedu.Reflection_;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectionQuestion {
public static void main(String[] args) throws Exception {
//传统的方法我们创建Cat对象
// Cat cat = new Cat("张三");
// cat.hi();
// 如果我们调用类创建对象,直接使用配置文件中的类和方法信息来创建对象
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullname = properties.getProperty("classfullname");
String method = properties.getProperty("method");
// System.out.println(classfullname);
// System.out.println(method);
//2.创建对象,使用传统方法行不通,
//new classfullname
//3. 使用反射机制解决(快速入门)
//(1)加载类 返回一个Class类型的对象,这个对象其实就是一个类
Class aClass = Class.forName(classfullname);
//(2)通过aClass对象,得到你加载的类的实例对象
Object o = aClass.getDeclaredConstructor().newInstance();
System.out.println(o.getClass());
// (3)通过aClass对象得到加载类的 method名字所代表的方法
//把方法视为对象
Method method1 = aClass.getMethod(method);
//通过method1 来调用方法 即方法对象来调用方法
method1.invoke(o);
}
}
```
### 2.2反射机制
1. 反射机制允许程序再执行期间借助于ReflectionAPI取得任何类的内部信息(如成员变量,构造器,底层方法等等),并且操作对象的属性及方法。反射在设计模式和框架底层都会用到
2. 加载完类之后,在堆中就产生了一个Class对象类型的对象(一个类只有一个Class对象),这个对象包含了完整的结构信息,通过这个对象得到类的信息。这个对象就像一面镜子,透过这个镜子看到了类的结构,所以称之为反射。
#### 2.2.1 java反射机制原理图

#### 2.2.2 java 反射机制可以完成
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员方法和变量
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
#### 2.2.3 反射相关的主要类
- java.lang.Class 代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method 代表类的方法
- java.lang.reflect.Field 代表类的成员变量
- java.lang.reflect.Constructor 代表类的构造方法
```java
// 获取类的成员变量
// 不能获取私有属性
Field nameField = aClass.getField("name");
System.out.println(nameField.get(o));
//用反射机制,Constructor 代表类的构造方法
Constructor[] constructors1 = aClass.getConstructors();// 返回构造器数组
System.out.println(constructors1[0]);
System.out.println(constructors1[1]);
System.out.println(constructors1[2]);
// Constructor[] constructors2 = aClass.getConstructors(String.class);
```
#### 2.2.4 反射优缺点
优点:可以动态创建对象和使用对象,使用灵活,没有反射机制,框架技术就失去底层支撑
缺点:使用反射基本是解释执行,对执行速度有影响
```java
package com.wjedu.Reflection_;
import java.lang.reflect.Method;
public class Reflection_time {
public static void main(String[] args) throws Exception {
m2();
m1();
m3();
}
public static void m1() throws Exception {
Class<?> aClass = Class.forName("com.wjedu.Reflection_.Cat");
Object o = aClass.getDeclaredConstructor().newInstance();
Method hi = aClass.getMethod("cry");
long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("执行时间是" + time);
}
public static void m2() {
Cat cat = new Cat();
long l = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
cat.cry();
}
long l1 = System.currentTimeMillis();
System.out.println(l1 - l);
}
//优化反射
public static void m3() throws Exception {
Class<?> aClass = Class.forName("com.wjedu.Reflection_.Cat");
Object o = aClass.getDeclaredConstructor().newInstance();
Method hi = aClass.getMethod("cry");
hi.setAccessible(true);//在反射调用方法时,取消访问检查
long start = System.currentTimeMillis();
for (int i = 0; i < 900000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("执行时间是" + time);
}
}
```
### 2.3 Class类
#### 2.3.1 类图

#### 2.3.2 基本介绍
1. Class也是类,也是继承Object类
2. Class类对象不是new出来的 而是系统创创建的(loadClass()方法加载 的)
3. 对于某个类Class类对象,在内存中只有一份,因为类只加载一次
4. 每个类的实例都会记得自己是有哪个Class实例所生成的
5. 通过Class可以完整的得到一个类的完整结构,通过一些列的API操作

1. Class对象是存放在堆中的
2. 类的字节码二进制数据,是放在方法区,有些地方成为类的元素据(包括方法代码,方法名,访问权限等 www.zhihu.com/question/38496907)
#### 2.3.3 Class类常用方法
```java
package com.wjedu.Reflection_;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Class_ {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//Class的方法
// 1.获取到Car类对应的Class对象
Class<?> aClass = Class.forName("com.wjedu.Reflection_.Car");
// 2.输出aClass
System.out.println(aClass);//显示的是哪个类的Class对象 class com.wjedu.Reflection_.Car
Class<? extends Class> aClass1 = aClass.getClass(); // 返回Class对象
System.out.println(aClass1);//输出cls运行类型 class java.lang.Class
//3 得到包名
Package aPackage = aClass.getPackage();
System.out.println(aPackage);
System.out.println(aPackage.getName());
//4 得到全类名 返回字符串类型
String name = aClass.getName();
//5 创建对象实例
Object o = aClass.getDeclaredConstructor().newInstance();
Car car = (Car)o;
System.out.println(car.toString());
//通过反射获取属性
Field color = aClass.getField("color");
System.out.println(color.get(car));
// 通过反射给属性赋值
color.set(car,"白色");
System.out.println(car.toString());
// 通过遍历获取所有属性
Field[] fields = aClass.getFields();
//System.out.println(fields[0].get(car));
for (Field f: fields) {
System.out.println(f.getName());
}
}
}
```
#### 2.3.4 获取Class类的对象6种方法

```java
package com.wjedu.Reflection_;
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
//通过Class.forNname()来获取
String allfullPath = "com.wjedu.Reflection_.Car";//通过读取配置文件
Class<?> aClass1 = Class.forName(allfullPath);
//通过 类名.class,用于传递参数
Class<Car> aClass2 = Car.class;
//通过对象获取 应用场景,有实例对象
Car car = new Car();
Class<? extends Car> aClass3 = car.getClass();
//通过类加载器获取到类的对象
//1.先得到类加载器
ClassLoader classLoader = car.getClass().getClassLoader();
//2.通过类加载器得到Class对象
Class<?> aClass4 = classLoader.loadClass(allfullPath);
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
System.out.println(aClass4.hashCode());
//基本数据类型 按照一下方法获取Class对象
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Double> doubleClass = double.class;
// 基本数据类型对象包装类,可以使用.TYPE得到Class类对象
Class<Integer> type = Integer.TYPE;
Class<Character> type1 = Character.TYPE;
}
}
```
#### 2.3.5 有哪些Class对象
如下类型有Class对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- 接口 interface
- 数组
- 枚举 enum
- 注解 annotation
- 基本数据类型
- void
### 2.4 类加载
#### 2.4.1 基本说明
反射机制是java实现动态语言的关键,反射实现类的动态加载、
1. 静态加载:编译运行时加载相关的类,如果没有则报错,依赖性强
2. 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低依赖
#### 2.4.2 类的加载时机
1. 对象创建时(new)
2. 当子类被加载时
3. 调用类中的静态成员时
4. 通过反射
#### 2.4.3类加载 过程


##### 1.加载阶段
JVM在该阶段主要是将字节码从不同的数据源(可能是class文件,也可能是jar包,甚至网络)转换为二进制字节流加载到内存中(方法区),并生成一个代表该类的java.lang.Class对象
##### 2.连接阶段-验证
1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的紫色安全
2.文件格式的验证、元数据验证、字节码验证和符号引用验证
3.可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
##### 2.链接阶段-准备
JVM会在该阶段堆静态变量,分配内存默认初始化(对应数据类型的初始值,如0,null false等)。这些变量所使用的内存都在方法区中进行分配。
```java
//3种不同的成员变量在链接阶段-准备 属性是如何处理的
public class A{
public Int n1 = 10;// 实例属性,准备阶段不分配内存
public static int n2 = 20; // 静态属性,准备阶段分配空间,默认初始化0
public static final int n3 = 30; //常量,一旦赋值,分配空间,赋值
}
```
##### 3.连接阶段-解析
虚拟机将常量池内的符号引用替换为直接引用的过程
##### 4.初始化 Initialization
1. 初始化阶段,才是真正执行类中定义JAVA程序代码,此阶段是执行<clinit>()方法过程
2. <clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值的动作和静态代码块中的语句,并进行合并
3. 虚拟机会保证一个类<clinit>()方法在多线程环境中被正确的加锁、同步、如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类<clinit>()方法,其他线程都需要阻塞等待,知道活动线程执行<clinit>()方法完毕
#### 2.4.4 通过反射获取类的结构信息
```JAVA
package com.wjedu.Reflection_;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionUtils {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {
String allfindPath = "com.wjedu.Reflection_.Car";
Class<?> aClass = Class.forName(allfindPath);
Object o = aClass.newInstance();
//获取类的全名
String name = aClass.getName();
System.out.println(name);
//获取简单的类名
String simpleName = aClass.getSimpleName();
System.out.println(simpleName);
//获取所有public修饰的属性,包含本类以及父类的
Field[] fields = aClass.getFields();
for (Field fie :fields) {
System.out.println(fie.getName());
}
System.out.println("-----------------------");
//获取所有public修饰的方法,包含本类和父类的
Method[] methods = aClass.getMethods();
for (Method me : methods) {
// System.out.println(me.getName());
}
System.out.println("-----------------------");
//获取本类中的所有方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method me : declaredMethods) {
System.out.println(me.getName());
}
// 获取所有public修饰的构造器 包含本类以及父类的
Constructor<?>[] constructors = aClass.getConstructors();
// 获取所有public修饰的本类构造器
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
//以package形式返回包信息
Package aPackage = aClass.getPackage();
System.out.println(aPackage.getName());
//以Class形式返回父类信息
Class<?> superclass = aClass.getSuperclass();
//返回接口信息,以Class[]
Class<?>[] interfaces = aClass.getInterfaces();
// 返回注解信息
Annotation[] annotations = aClass.getAnnotations();
}
}
```
### 2.5 通过反射爆破创建对象
```java
package com.wjedu.Reflection_;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
* 通过反射机制创建实例对象
* */
public class ReflectionCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//方式1 调用类中的public修饰的无参构造器
// 获取User类的Class对象
Class<?> aClass = Class.forName("com.wjedu.Reflection_.User");
Object o = aClass.newInstance();// jdk8 创建实例对象
System.out.println(o);
Object obj = aClass.getDeclaredConstructor().newInstance();//jdk9以上
System.out.println(obj);
// 方式2 调用类中的有参构造器
Constructor con1 = aClass.getDeclaredConstructor(String.class);
Object obj2 = con1.newInstance("王五");
System.out.println(obj2);
//方式3 调用类中的私有的有参构造器
Constructor<?> con3 = aClass.getDeclaredConstructor(int.class,String.class);
con3.setAccessible(true);
Object obj3 = con3.newInstance(36, "张三丰");//IllegalAccessException 需要爆破私有方法
System.out.println(obj3);
}
}
class User{
public int age = 10;
public String name = "小张无忌";
public User() {
}
public User(String name){
this.name = name;
}
private User(int age,String name){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
```
### 2.6 通过反射访问类中的成员
```java
package com.wjedu.Reflection_;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
* 通过反射机制访问成员变量
* */
public class ReflectionAccessProperty {
public static void main(String[] args) throws Exception{
//创建Studeng类的对象
Class<?> aClass = Class.forName("com.wjedu.Reflection_.Student");
Constructor<?> con1 = aClass.getConstructor();
Object o = con1.newInstance();
//操作public成员对象
Field age = aClass.getField("age");
age.set(o,18);// 设置对象
System.out.println(o);
System.out.println(age.get(o));//获取对象
//操作private成员对象
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);
name.set(o,"王五");
name.set(null,"jack");// 静态成员可以写空
System.out.println(name.get(o));
}
}
class Student{
public int age;
private static String name;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
```
### 2.7 通过反射访问方法
```java
package com.wjedu.Reflection_;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionAccessMethod {
public static void main(String[] args) throws Exception {
//创建Boss类的实例对象
Class<?> aClass = Class.forName("com.wjedu.Reflection_.Boss");
// 创建对象
Constructor<?> con1 = aClass.getDeclaredConstructor();
Object o = con1.newInstance();
//根据方法名和参数列表获取method对象方法
Method method = aClass.getMethod("hi",String.class);
Object jack = method.invoke(o, "jack");
//爆破访问私有方法
Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);
Object invoke = say.invoke(o, 15, "tom", '男');//私有方法不爆破 IllegalAccessException
System.out.println(invoke);
}
}
class Boss {
public int age;
private static String name;
public Boss() {
}
private static String say(int n, String s, char c) {
return n + " " + s + " " + c;
}
public void hi(String s) {
System.out.println("hi " + s);
}
}
```