比较重要的点:
获取类对象的三种方式**
1 类名.class 2 对象.getClass() 3 Class.forName(str)
类对象常用的方法 newInstance() 获取某个类的对象(调用某个类的空参构造方法)
类 Class Class.forName() .newInstance()
属性 Field set(obj,value) get()
构造方法 Constructor newInstance()
方法 Method invoke(obj,value)
参数 Parameter getType() 参数类型
工厂模式:通过工厂类产生对象,利用反射动态产生对象
单例模式: (1)构造方法私有化 (2)提供一个公有的方法,返回实例
饿汉式:类加载时实例就会被创建,优点是线程安全,缺点资源浪费
懒汉式:调用时方法时,实例才会创建,优点节约资源,缺点线程不安全 ( DCL(双重检测锁) + volatile 或 静态内部类 )
枚举:本质上是终态类,属性本质上当前类型的静态常量
注解: 元注解@Target 作用范围 TYPE 类、FIELD 属性、 METHOD 方法、PARAMETER 参数
@Retention 生命周期 RUNTIME 运行阶段有效
类对象
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法) 。
注意:每个类加载到内存都会生成一个唯一的类对象。
获取类对象的三种方式
1、通过对象的getClass方法
2、通过类的class属性
3、通过Class类的forName方法
public static void test01(){
//1、通过对象的getClass方法
//Student stu = new Student();
//Class c = stu.getClass();
//class com.qf.reflect.Student 全的限定名(包名+类名)
//System.out.println(c);
//2、通过类的class属性
//Class c = Student.class;
//class com.qf.reflect.Student
//System.out.println(c);
//3、通过Class类的forName方法 参数:全限定名 (此方法的作用:1、触发类加载 2、获取类对象)
try {
Class c = Class.forName("com.qf.reflect.Student");
System.out.println(c);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Filed类
Field类表示类对象中的属性
获取它的目的:赋值和取值
public static void test04(){
try {
//1、获取类对象
Class c = Class.forName("com.qf.reflect.Student");
Object o = c.newInstance();//确保1、无参构造2、public修饰
//获取指定公开的属性
//Field field = c.getField("money");
//对属性进行赋值
//field.set(o,200.55);
//获取属性中的值
//System.out.println(field.get(o));
//获取所有公开的属性(包括父类的)
//Field[] fields = c.getFields();
//System.out.println(Arrays.toString(fields));
//获取执行的私有属性
//Field field = c.getDeclaredField("name");
//暴力反射
//field.setAccessible(true);
//field.set(o,"张三");
//System.out.println(field.get(o));
//获取所有的属性(包括私有的)
Field[] fields = c.getDeclaredFields();
System.out.println(Arrays.toString(fields));
} catch (Exception e) {
e.printStackTrace();
}
}
Constructor类
Constructor类表示类对象中的方法
获取它的目的,创建对象
public static void test03(){
try {
//1、获取类对象
Class c = Class.forName("com.qf.reflect.Student");
//获取这个类的指定的构造方法
//Constructor constructor = c.getConstructor(String.class, int.class);
//通过构造方法new对象
//Object stu = constructor.newInstance("张三",30);
//System.out.println(stu);
//获取所有公开的构造方法
// onstructor[] constructors = c.getConstructors();
//System.out.println(Arrays.toString(constructors));
//获取所有的构造方法(包括私有的)
//Constructor[] constructors = c.getDeclaredConstructors();
//System.out.println(Arrays.toString(constructors));
//获取指定私有的无参构造方法
Constructor constructor = c.getDeclaredConstructor();
//设置私有可以访问(暴力反射)
constructor.setAccessible(true);
Object o = constructor.newInstance();
System.out.println(o);
} catch (Exception e) {
e.printStackTrace();
}
}
Method类
Method类表示类对象的方法
获取它的目的,调用它并获取方法的返回值(如果方法没有返回值则返回null)
public static void test05(){
try {
//1、获取类对象
Class c = Class.forName("com.qf.reflect.Student");
Object o = c.newInstance();
//获取指定公开的方法
//Method method = c.getMethod("show", String.class);
//利用反射调用方法,并接收返回值
//Object result = method.invoke(o, "wuwu,网比较卡");
//System.out.println(result);
//获取所有的公开的方法(包括父类的公开的方法)
//Method[] methods = c.getMethods();
//System.out.println(Arrays.toString(methods));
//获取指定的私有方法
//Method method = c.getDeclaredMethod("print");
//method.setAccessible(true);
//利用反射调用方法,并接收返回值(如果方法没有返回值。那么invoke方法就返回null)
//Object result = method.invoke(o);
//System.out.println(result);
//获取本类中所有的方法(包括私有的)
Method[] methods = c.getDeclaredMethods();
System.out.println(Arrays.toString(methods));
} catch (Exception e) {
e.printStackTrace();
}
}
工厂模式
开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。
//Phone接口
public interface Phone {
public void call();
public void recive();
}
//手机类
public class HuaWeiPhone implements Phone{
@Override
public void call() {
System.out.println("华为手机打电话");
}
@Override
public void recive() {
System.out.println("华为手机接电话");
}
}
public class XiaoMiPhone implements Phone{
@Override
public void call() {
System.out.println("小米手机打电话");
}
@Override
public void recive() {
System.out.println("小米手机接电话");
}
}
//利用反射创建对象
public class PhoneFactory {
/**
* 利用反射,创建工厂类创建对象
* @param className
* @return
*/
public static Phone getPhoneRef(String className){
try {
Class<?> pClass = Class.forName(className);
Phone phone = (Phone) pClass.newInstance();
return phone;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
Phone xmPhone = PhoneFactory.getPhoneRef("com.qf.factory.XiaoMiPhone");
xmPhone.call();
xmPhone.recive();
Phone hwPhone = PhoneFactory.getPhoneRef("com.qf.factory.HuaWeiPhone");
hwPhone.call();
hwPhone.recive();
}
}
//bean.properties文件建在src下边,格式:key=value
//有一个接口,具体类实现接口,利用接口创建具体类对象
public class BeanFactory {
private static Map<String,Object> map=new HashMap<String,Object>();
static {
try {
Properties properties = new Properties();
//读取src下的properties文件
properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
//读取文件的key值集合
Set<Object> set = properties.keySet();
for (Object s:set){
//获取类对象
Class<?> pClass = Class.forName((String) properties.get(s));
//创建对象
Object v = pClass.newInstance();
//将key和创建的对象加到map
map.put((String) s,v);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static Phone getPhoneBean(String name){
return (Phone) map.get(name);
}
}
单例模式
让类的对象只能有唯一的一个实例
单例分类:
懒汉式
- 好处:避免资源浪费(需要对象的时候就创建对象)
- 缺点 :线程不安全
- 解决:
- 1、DCL(双重检测锁) +volatile
- DCL的问题:
- 解决:volatile关键字修饰 1、避免指令重排 2、多线程可见性
- 2、使用静态内部类(什么时候使用静态内部类,什么时候就加载)
饿汉式
- 1、DCL(双重检测锁) +volatile
- 好处:线程安全。
- 缺点:浪费资源。只要类被加载,那么这个类实例就会被创建
如何实现单例 - 1、私有化构造方法
- 2、提供一个方法,返回这个类的实例
反射破坏单例的问题:
解决:在构造方法中加上判断,如果对象不为空则直接抛出异常
饿汉式
public class Singleton01 {
private static Singleton01 singleton01 = new Singleton01();
private Singleton01(){
}
public static Singleton01 getInstance(){
return singleton01;
}
}
懒汉式(DCL解决)
public class Singleton02 {
private static volatile Singleton02 singleton02; //volatile
private Singleton02(){
}
public static Singleton02 getInstance(){
//双重检验锁 DCL(double check lock) 1、指令重排 2、可见性(在多线程间可见)
if(singleton02 == null){
synchronized (Singleton02.class){//互斥锁标记
if(singleton02 == null){
//java中允许指令重排序
singleton02 = new Singleton02();
}
}
}
return singleton02;
}
}
懒汉式单例(静态内部类)
public class Singleton03 {
private Singleton03(){}
public static Singleton03 getInstance(){
return Holder.singleton03;
}
//静态内部类(什么时候使用静态内部类,什么时候就加载)
public static class Holder{
private static Singleton03 singleton03 = new Singleton03();
}
}
反射破坏单例(任何单例都会遭到反射的破坏,因为反射可以直接执行私有的构造方法)
private static volatile Singleton02 singleton02;
private static Object obj = new Object();
private Singleton02(){
if(singleton02 != null){
throw new IllegalArgumentException("不要试图使用反射破坏单例");
}
}
枚举
枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。
一般已经确定类的对象个数,可以使用枚举定义
枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。
定义枚举使用enum关键字。
枚举的本质:
枚举是一个终态类,并继承Enum抽象类。
枚举中常量是当前类型的静态常量。
public enum Color {
//枚举类的三个实例
RED,GREEN,YELLOW;
//可以定义属性、方法
private String name;
public void show(){
System.out.println("show...");
}
//定义构造方法(必须私有)
private Color(){}
private Color(String title){
}
}
注意:
枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法。
枚举常量必须在前面,多个常量之间使用逗号隔开,如果没有定义其他内容,最后分号可写可不写。
注解
注解(Annotation):是代码里的特殊标记, 程序可以读取注解,一般用于替代配置文件。
定义注解使用@interface关键字,注解中只能包含属性。
常见注解:@Override
注解注意事项
- 1、注解中只能是属性 ,本质上是抽象方法
- 2、如果注解中属性只有一个必填注解,且是value。那么使用的时候,value=可以省略
- 3、如果属性有默认值,那么在使用的时候可以不填
- 4、如果属性是一个数组,那么在使用的时候如果只有一个参数,大括号可以省略
元注解
加在注解上的注解
@Retention:定义注解的使用范围
- Class (默认的) class源文件期间保留
- Source 编译期间保留
- Runtime 在运行期保留
@Target: 定义注解的使用范围
- TYPE, 类上使用
- FIELD, 属性上使用
- METHOD, 方法上使用
- PARAMETER, 参数上使用
注解的示例
//注解定义
//只能用在类上
@Target(ElementType.TYPE)
//运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
String name();
}
//注解的应用
@TableName(name = "tb_user")
public class User {
}
@TableName(name = "tb_man")
public class Man {
}
//使用
public class Test1 {
public static String getsql(String name) throws ClassNotFoundException {
Class<?> aClass = Class.forName(name);
TableName annotation = aClass.getAnnotation(TableName.class);
String s = annotation.name();
return "select * from "+s;
}
public static void main(String[] args) throws ClassNotFoundException {
System.out.println(getsql("com.qf.demo.User"));
System.out.println(getsql("com.qf.demo.Man"));
}
}