JAVA从入门到精通------基础篇------反射(初学者必看)
1、反射
类的对象:基于某个类new出来的对象,也称为实例对象
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法)
2、获取类对象
通过类的对象,获取类对象
Student s = new Studnet();
Class c = s.getClass();
通过类名获取类对象
Class c = 类名.class;
通过静态方法获取类对象
Class c = Class.forName(“包名.类名”);
3、常用方法
1)获取类对象方式
//第一种方式
Class class1 = Student.class;
//第二种方式
Student zhangsan = new Student();
Class class2 = zhangsan.getClass();
//第三种方式-------> 最常用的一种方式 但是需要try-catch
//类名.包名指定------> 因为不同包下类名可以相同一样需要指定
Class class3 = Class.forName("com,java.day24.Student")
2)获取对象的类名及包名
//可以通过类对象获取类的信息
//类名、父类、接口、方法、属性、构造方法
class1.getName();
3)获取该类的父类的类名及包名
//获取父类
Class superClass = class1.getSuperclass()
//父类的名字
superClass.getName();
4)获取hashCode值
//获取hashCode值
class1.hashCode();
5)获取包名
//包名
class1.getPackage().getName();
6)获取类所实现的接口
Class[] aryInterface = class1.getInterfaces();
for(Class c : aryInterface){
System.out.println(c);
}
7)获取类的方法及相关属性
//使用getConstructors()方法进行调取
//因为类里的构造方法可能有很多所以我们定义一个Constructor[]数组进行接收
//增强for循环进行遍历
//通过调取方法可以调取方法里的修饰符,构造方法名,参数个数
Constructor[] constructor = class1.getConstructors();
for(Constructor c : constructor){
System.out.println(c);
//调取方法的修饰符
c.getModifiers();
//调取构造方法名
c.getName();
//调取参数个数
c.getParameterCount();
}
8)通过无参构造方法创建类的对象
第一种方式:
//先获取无参构造方法
Constructor cons1 = class1.getConstructor();
//通过构造方法对象,来创建类的对象
//先用Constructor获取构造方法
//再将得到的构造方法.newInstance来获得对象
//强制转换
Student lisi = (Student)cons1.newInstance();
System.out.println(lisi);
第二种方式:
//获取无参构造方法
Constructor cons1 = class1.getConstructor();
//通过类对象直接创建对象
//直接用代表类具体位置的class1通过它调用newInstance方法创建对象
//强制转换
Student wangwu = (Studnet)class1.newInstance();
System.out.println(wangwu);
9)通过有参构造方法创建类的对象
//获取某个有参构造方法
//String.class和int.class是因为以往我们传参数直接传,
//现在因为我们用反射所以先把数据类型的地址传进来
Constructor cons2 = class1.getConstructor(String.class, int.class);
//通过有参构造方法创建对象
Student huangliu = (Student)cons2.newInstance("黄六", 46);
System.out.println(huangliu);
10)获取类对象的public修饰的方法
//包括其父类的方法
//如果子类重写了父类的方法那么就不会显示父类的
//只会显示父类里没有重写的方法
Method[] aryMethod = class1.getMethods();
for(Method m : aryMethod){
System.out.println(m);
}
11)获取当前类中的所有方法
Method[] newAryMethod = class1.getDeclaredMethods();
for(Method m : newAryMethod){
System.out.println(m);
}
12)调用该类普通的无参方法
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//再获取该方法
Method methodTest1 = class1.getMethod("sayHi");
//传对象 调方法
methodTest1.invoke(huangliu);
13)调用该类普通的有参方法
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//再获取该方法以及传参的数据类型的类型
Method methodTest2 = class1.getMethod("sayHi", String.class, int.class);
//传对象 调方法
methodTest2.invoke(huangliu, "黄六", 46);
14)调用私有属性修饰的无参方法
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//获取无参私有方法
Method privateMethod1 = class1.getDeclaredMethod("privateTest");
//定义为true可以调用
privateMethod1.setAccessible(true);
//调用方法----------无参方法
privateMethod1.invoke(huangliu);
15)调用私有属性修饰的有参方法
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//获取有参私有方法
Method privateMethod2 = class1.getDeclaredMethod("privateTest", String.class);
//定义为true可以调用
privateMethod2.Accessible(true);
//调用方法----------有参方法
privateMethod2.invoke(huangliu, "abc");
16)调用无参static方法
//获取static方法
Method staticMethod1 = class1.getMethod("staticTest");
//调用方法---------无参方法
staticMethod1.invoke(null);
17)调用有参static方法
//获取static方法
Method staticMethod2 = class1.getMethod("staticTest", String.class);
//调用方法--------有参方法
staticMethod2.invoke(null, "abc");
18)获取包括父类在内的所有publc属性
Field[] aryFiled = class1.getFields();
for(Field f : aryField){
System.out.println(f);
}
19)给类中的属性赋值并调用
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//先获取属性
Field addField = class1.getField("addr");
//public属性赋值
//set赋值
addField.set(huangliu, "北京市海淀区");
//值赋进去之后get得到传进的变量名就可以
addField.get(huangliu);
20)获取本类中所有的属性
//获取本类所有属性 public、默认、private、protected等
Field[] allF = class1.getDeclaredFields();
for(Field a " allF){
System.out.println(a);
}
21)给私有属性赋值并调用
//获取构造器 可选择有参 无参两种方式
Constructor cons2 = class1.getConstructor(String.class, int.class);
//再new对象 可选择有参 无参两种方式
Student huangliu = (Student)cons2.newInstance("黄六", 46);
//获取属性
Field ageField = class1.getDeclaredField("age");
//设置为可以访问
ageField.setAccessible(true);
//set赋值
ageField.set(haungliu, 48);
//值赋进去之后get得到传进变量名就可以
ageField.get(huangliu);
public class Person {
public int heart;
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person() {
super();
}
public Person(String sex) {
super();
this.sex = sex;
}
public void sayHi() {
System.out.println("执行了父类中的sayHi方法");
}
}
public class Student extends Person implements eat, play{
public String addr;
public int money;
private String name;
private int age;
public Student() {
super();
}
public Student(String name) {
super();
this.name = name;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 void sayHi() {
System.out.println("执行了子类中的无参sayHi方法");
}
public void sayHi(String name,int age) {
System.out.println("执行了子类中的有参sayHi方法");
}
private void privateTest() {
System.out.println("执行了Student子类当中的无参私有方法privateTest");
}
private void privateTest(String str) {
System.out.println("执行了Student子类当中的有参私有方法privateTest" + str);
}
public static void staticTest() {
System.out.println("执行了Student子类当中的无参static方法staticTest");
}
public static void staticTest(String str) {
System.out.println("执行了Student子类当中的有参static方法staticTest" + str);
}
@Override
public void interfaceEat() {
System.out.println("执行了interfaceEat方法");
}
@Override
public void interfacePlay() {
System.out.println("执行了interfacePlay方法");
}
@Override
public String toString() {
return "Student [name=" + name + ", stuNo=" + age + "]";
}
}
import java.io.ObjectInputStream.GetField;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo2 {
public static void main(String[] args) {
//获取类对象方式1
//获取类的具体位置
Class class1 = Student.class;
System.out.println(class1);
//获取类对象方式2
Student zhangsan = new Student();
Class class2 = zhangsan.getClass();
System.out.println(class2);
try {
//获取类对象方式3
//类名.包名指定------> 因为类名不同包下可以一样需要指定
Class class3 = Class.forName("com.qf.javasepro2105.day24.Student");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//可以通过类对象获取类的信息
//类名 父类 接口 方法 属性 构造方法
System.out.println("类的名字:" + class1.getName());
//获取Student的父类
Class superClass = class1.getSuperclass();
System.out.println("父类的名字:" + superClass.getName());
//判断hashCode值从而判断是不是同一个
System.out.println(class1.hashCode());
System.out.println(class2.hashCode());
System.out.println("包名:" + class1.getPackage().getName());
//获取学生类Student 实现的接口的类对象
Class[] aryInterface = class1.getInterfaces();
for(Class c : aryInterface) {
System.out.println(c);
}
//获取Student的构造方法
//使用getConstructors()方法进行调取
//因为类里的构造方法可能有很多所以我们定义一个Constructor[]数组进行接收
//增强for循环进行遍历
//通过调取方法可以调取方法里的修饰符,构造方法名,参数个数
Constructor[] constructor = class1.getConstructors();
for(Constructor c : constructor) {
System.out.println(c);
System.out.println("方法的修饰符:" + c.getModifiers() + ",构造方法名"
+c.getName()+",参数个数:" + c.getParameterCount());
}
System.out.println("----------------------------");
try {
//获取无参构造方法
Constructor cons1 = class1.getConstructor();
//通过构造方法对象,来创建类的对象
//先用Constructor获取构造方法
//再将得到的构造方法.newInstance就可以获得对象了
Student lisi = (Student)cons1.newInstance();
System.out.println(lisi);
//通过类对象直接创建对象
//直接用代表类具体位置的class1通过它调用newInstance方法创建对象
Student wangwu = (Student)class1.newInstance();
System.out.println(wangwu);
//获取某个有参构造方法
//String.class和int.class是因为以往我们传参数直接传,
//现在因为我们用反射所以先把数据类型的地址传进来
Constructor cons2 = class1.getConstructor(String.class, int.class);
//通过有参构造方法创建对象
Student huangliu = (Student)cons2.newInstance("黄六", 46);
System.out.println(huangliu);
//获取类对象的普通的public的方法
//包括其父类的方法
//如果子类重写了父类的方法那么就不会显示 只会显示父类里没有重写的方法
Method[] aryMethod = class1.getMethods();
System.out.println("Studnet类的public方法如下:");
for(Method m : aryMethod) {
System.out.println(m);
}
//获取类中的所有方法:private public 默认 protected等
//只获取当前类中的方法
//通过getDeclaredMethods()进行调用当前类中的所有方法
Method[] newAryMethod = class1.getDeclaredMethods();
System.out.println("Student类的所有方法如下:----------");
for(Method m : newAryMethod) {
System.out.println(m);
}
//获取某个普通方法
Method methodTest1 = class1.getMethod("sayHi");
Method methodTest2 = class1.getMethod("sayHi", String.class, int.class);
System.out.println("======================================");
//调用方法----------无参方法
methodTest1.invoke(huangliu);
//调用方法----------有参方法
methodTest2.invoke(huangliu, "黄六", 46);
System.out.println("调用私有方法:》》》》》》》》》》》》》》》》》》》》》");
//获取私有方法:但是这样破坏了安全性
Method privateMethod1 = class1.getDeclaredMethod("privateTest");
Method privateMethod2 = class2.getDeclaredMethod("privateTest", String.class);
privateMethod1.setAccessible(true);
privateMethod2.setAccessible(true);
//调用方法----------无参方法
privateMethod1.invoke(huangliu);
//调用方法----------有参方法
privateMethod2.invoke(huangliu, "abc");
System.out.println("调用静态方法:++++++++++++++++++++++++++++++++++");
//获取static方法
Method staticMethod1 = class1.getMethod("staticTest");
Method staticMethod2 = class1.getDeclaredMethod("staticTest", String.class);
//调用方法----------无参方法
staticMethod1.invoke(null);
//调用方法----------有参方法
staticMethod2.invoke(null,"abc");
System.out.println("");
System.out.println("");
//获取包括父类在内的public属性
Field[] aryField = class1.getFields();
System.out.println("public属性如下:");
for(Field f : aryField) {
System.out.println(f);
}
System.out.println("");
//获取某个属性
Field addField = class1.getField("addr");
//public属性赋值
//set赋值
addField.set(huangliu, "北京市海淀区");
//值赋进去之后get得到传进变量名就可以
System.out.println("public属性addr的属性值是:" + addField.get(huangliu));
//获取本类所有属性:public 默认 private protected等
Field[] allF= class1.getDeclaredFields();
System.out.println("本类中所有属性遍历如下");
for(Field a : allF) {
System.out.println(a);
}
Field ageField = class1.getDeclaredField("age");
//设置为可以访问
ageField.setAccessible(true);
//set赋值
ageField.set(huangliu, 48);
//值赋进去之后get得到传进变量名就可以
System.out.println("private属性age的属性值是:" + ageField.get(huangliu));
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4、设计模式
什么是设计模式
一套被反复使用,多数人知晓的,经过分类编目的、代码设计经验的总结
可以简单理解为特定问题的固定解决方法
好处:
使用设计模式是为了可重用代码、让代码容易被他人理解,保证代码可靠性、重用性
5、工厂设计模式
开发中有一个非常重要的原则"开闭原则",对扩展开放、对修改关闭
工厂模式主要负责对象创建的问题
可通过反射进行工厂模式的设计,完成动态的对象创建
//封装属性
public class Animal {
private String name;
private char sex;
private int age;
public Animal() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Animal(String name, char sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Animal [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
//继承父类 封装属性 写子类属性
public class Dog extends Animal{
private String strain;
public Dog() {
super();
// TODO Auto-generated constructor stub
}
public Dog(String name, char sex, int age, String strain) {
super(name, sex, age);
this.strain = strain;
}
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
@Override
public String toString() {
return "Dog [strain=" + strain + ", toString()=" + super.toString() + "]";
}
}
//继承父类 封装属性 写子类属性
public class Cat extends Animal{
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Cat() {
super();
// TODO Auto-generated constructor stub
}
public Cat(String name, char sex, int age, String color) {
super(name, sex, age);
this.color = color;
}
@Override
public String toString() {
return "Cat [color=" + color + ", toString()=" + super.toString() + "]";
}
}
public class AnimalFactory {
//出父类和子类的属性以外再定义一个type用来确定newn哪个,c就是cat d就是dog
public static Animal creatAnimal(String name, char sex, int age,
String color, String strain, char type) {
//lsp原则new子类对象因为子类tostring重写了包括父子类所以调用时自己找对应的子类
Animal animal = null;
switch(type) {
//c是cat
case 'c':
animal = new Cat(name,sex,age,color);
break;
//d是dog
case 'd':
animal = new Dog(name,sex,age,strain);
break;
}
return animal;
}
}
public class Demo1 {
public static void main(String[] args) {
//赋值调用
Cat tt = (Cat)AnimalFactory.creatAnimal("旺财", '男', 6, "白色", "中国", 'c');
System.out.println(tt);
Dog wangcai = (Dog)AnimalFactory.creatAnimal("大黄", '女', 4, "黄色",
"狼狗", 'd');
System.out.println(wangcai);
}
}
6、单例模式
//饿汉式
public class Pet {
//先创建一个私有构造方法确保只能构造一次
private Pet() {
}
//创建一个对象 我们给new出来让他们只能调用
private static Pet pet = new Pet();
//写一个public的方法确保可以调用
public static Pet Test() {
return pet;
}
}
//懒汉式
//此时不安全
public class Pet {
private Pet() {
}
private static Pet pet;
public static Pet Test() {
if(pet == null) {
pet = new Pet();
}
return pet;
}
}
//懒汉式
//此时安全
public class Pet {
private Pet() {
}
private static Pet pet;
public static Pet Test() {
synchronized ("abc") {
if(pet == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pet = new Pet();
}
}
return pet;
}
}
//懒汉式
//此时安全
public class Pet {
private Pet() {
}
private static Pet pet;
public static Pet Test() {
synchronized ("abc") {
if(pet == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pet = new Pet();
}
}
return pet;
}
}
public class Animal1 extends Thread{
@Override
public void run() {
//将方法得到
Pet qq = Pet.Test();
System.out.println("Animal1获得到的对象地址是" + qq);
}
}
public class Animal2 extends Thread{
@Override
public void run() {
Pet kugou = Pet.Test();
System.out.println("Animal2获得到的对象地址是" + kugou);
}
}
public class Demo1 {
public static void main(String[] args) {
//因为继承了Thread类所以new出来之后 直接start就可以
Animal1 cat = new Animal1();
Animal2 dog = new Animal2();
cat.start();
dog.start();
}
}
7、枚举
什么是枚举:
枚举是一种引用类型,枚举是一个规定了取值范围的数据类型
枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性
定义枚举使用enum关键字
枚举的本质:
枚举是一个终止类,并继承Enum抽象类
枚举中常量是当前类型的静态常量
public enum Enum1 {
春季,夏季,秋季,冬季
}
public class Demo4 {
public static void main(String[] args) {
Enum1 Venum = Enum1.春季;
System.out.println(Venum);
}
}
8、注解
什么是注解:
注解(Annotation)是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件
开发人员可以通过注解告诉类如何运行
再JAVA技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类
常见注解:@Override @Deprecated
定义注解使用 @Interface关键字,注解中只能包含属性
元注解:用来描述注解的注解
@Retention:用于指定注解可以保留的域
RetentionPolicy.Class
注解记录在class文件中,运行java程序时,JVM不会保留,此为默认值
不写的时候也存在
------------------------------
不用注解里的东西
==================
RetentionPolicy.RUNTIME
注解记录在class文件中,运行java程序时,JVM会保留,程序可以通过反射获取该注释,加载时候加载进去,作用就是用来反射时候获取
--------------------------------
调用注解里的东西
=================
RetentionPolicy.SOURCE
编译时直接丢弃这种策略的注释,编译时候就不编译了
--------------------------------
用一次不用了
==================
@Target
指定注解用于修饰类的哪个成员 ,告诉注解运行在哪里
ANNOTATION
CONSTRUCTOR 构造器 构造方法
FIELD 属性
LOCAL_VARIABLE 局部变量
METHOD 方法
PACKAGE 包
PARAMETER
TYPE
TYPE_PARAMETER
TYPE_USE
注解是为了给反射用的,如果new对象之后调用方法还是要传参
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//用来确定写的这个方法是否调用
@Retention(value = RetentionPolicy.RUNTIME)
//定义 在方法中才可以调用
@Target(value = ElementType.METHOD)
//@Target(value = ElementType.FIELD)
//写一个接口接口里边写逻辑语句用来调用
public @interface Mdv {
String name() default "张三";
int age() default 18;
}
public class Person {
// //如果不写这行
// @Mdv(name = "王五", age = 66)
//写这行就是默认值
@Mdv
public static void sayHi(String name, int age) {
System.out.println("名字是:" + name + "年龄是" + age);
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
//再用反射去调用注解
//因为有异常所以先赋值给null
Class class1 = null;
try {
//将personnnew通过反射调取出地址
class1 = Class.forName("com.qf.javasepro2105.day25.s1.Person");
//通过地址调取出方法
Method sayHiMethod = class1.getMethod("sayHi", String.class, int.class);
//通过方法调取注解
//通过注解.class去确定类型以便于传参的时候是类型是注解的类型
Mdv mdv = sayHiMethod.getAnnotation(Mdv.class);
//因为调用方法,需要传person对象
Person person = (Person)class1.newInstance();
sayHiMethod.invoke(person, mdv.name(), mdv.age());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}