1.泛型<>
在集合里面 最早的接触的泛型 <K,V,E,T> T,K, V 参数化类型: 任意引用数据类型 A-Z
泛型的主要作用: 类型自动转换。
泛型只在编译期间有效 运行期间泛型是无效 class 泛型已经没有作用(泛型擦除)
1.1 泛型类
public class MyFanXingClass<K, V> {
private K k;
private V v;
//不是泛型方法 : 参数化类型充当形参和返回值罢了
//set/get里面k,v 严格参照创建MyFanXingClass类对象时候的k v 类型
public K getK() {
return k;
}
public void setK(K k) {
this.k = k;
}
public V getV() {
return v;
}
public void setV(V v) {
this.v = v;
}
public V demo(K k1) {
System.out.println("k1:" + k1);
return v;
}
//泛型方法: 在方法定义上 加一个<K>
//泛型方法里面 参数化类型与创建对象时候的类型 不一定是一致
//要参考方法上的: <K,A,V>
public <K, A> V demo1(K k2, A a) {
System.out.println("k2:" + k2);
System.out.println("a:" + a);
return null;
}
//静态方法: 类
//在一个泛型类里面 有静态方法
//前提: 参数化类型充当方法的形参 返回值
//这个静态方法必然就是一个泛型方法
public static <K, T> T demo2(K k3) {
System.out.println("k3:" + k3);
return null;
}
}
1.2 泛型接口
场景:
用户模块: User.java
crud
商品模块:
crud
订单模块:
crud
public interface BaseDao<T, S> {
void add(T t);
void delete(S s);
void select(S s);
void update(T t);
}
public abstract class BaseDaoImpl<T, S> implements BaseDao<T, S> {
//T S 模拟: MP mybatis-plus.jar BaseMapper.java
//获得参数化类型的真实类型
//反射
@Override
public void add(T t) {
}
//.................
}
public interface UserDao extends BaseDao<User,String> {
//用户模块独有的功能方法
}
public class UserDaoImpl extends BaseDaoImpl<User, String> implements UserDao {
}
1.3 泛型上/下限
public class FanXingClass<T extends Number> {
//上限
//T 可以是任意的引用数据类型 Object的子类
//T 只能是Number类的子类 也可以Number类
//下限
// ? 泛型通配符 Class 统配T 的任意类型
public void a(FanXingClass<? super Number> obj) {
}
//下限: ? ArrayList 或者 ArrayList的父类
public void b(Class<? super Comparable<T>> clazz) {
}
// ? 统配所有的参数化类型
public void c(Class<?> clazz) {
}
public static void main(String[] args) {
FanXingClass<Number> fanXingClass = new FanXingClass<>();
Class<AbstractList> listClass = AbstractList.class;
// fanXingClass.b(listClass);
//
// fanXingClass.a(fanXingClass);
// Object obj = new Object();
// obj.getClass()
}
2. 枚举
Thread.State ChronoField ChroneUnit DayOfWeek Month
public enum 枚举类名称{
//成员
对象(实例 常量 不可变的 唯一的 单例)
方法
属性
构造
}
public enum MyEnum {
//维护不可变的数据
// 对象(实例 常量 不可变的 唯一的 单例)
// 方法
// 属性
// 构造
//枚举类的对象(默认通过无参构造创建对象)
MONDAY(1, "星期一") {
//方法重写
@Override
public void a() {
System.out.println("重写a。。。。。。");
}
},
TUESDAY(2, "星期二"),
SUNDAY(7, "星期日");
private Integer id;
private String name;
public void a() {
System.out.println("a.....");
}
public final Integer getId() {
return id;
}
public final String getName() {
return name;
}
MyEnum(Integer id, String name) {
this.id = id;
this.name = name;
}
// MyEnum() {
// //默认存在无参构造 (所有的构造都是private)
// }
}
2.1 泛型+枚举类
根据数据分析 设计类 设计方法
{
"message": "CityId100030200不在返回之内,",
"status": 403
}
{
"message": "success",
"status": 200,
"data":{
//什么类型的额数据 不定的 url(接口)--->作用到程序里面的方法
}
https://www.sojson.com/blog/305.html
http://t.weather.itboy.net/api/weather/city/101030100
@Setter
@Getter
@ToString
public class ServerResponseResult<T> {
//里面所有的构造都是私有的
private ServerResponseResult() {
}
private String message;//成功/失败的信息
private Integer status;//成功/失败的状态 肯定都是固定的
private T data;//成功时候的数据
private ServerResponseResult(String message, Integer status, T data) {
this.message = message;
this.status = status;
this.data = data;
}
private ServerResponseResult(String message, Integer status) {
this.message = message;
this.status = status;
}
//通过静态方法处理: 类对象
public static <T> ServerResponseResult<T> success(String message, Integer status, T data) {
return new ServerResponseResult<>(message, status, data);
}
public static <T> ServerResponseResult<T> success(T data) {
return new ServerResponseResult<>(CodeEnum.SUCCESS.getMsg(), CodeEnum.SUCCESS.getCode(), data);
}
public static <T> ServerResponseResult<T> error(String message, Integer status) {
return new ServerResponseResult<>(message, status);
}
public static <T> ServerResponseResult<T> error() {
return new ServerResponseResult<>(CodeEnum.ERROR.getMsg(), CodeEnum.ERROR.getCode());
}
}
3.单例
单例模式。 java语言23种设计模式其中之一。
在一个进程里面有且只有一个实例。 (一个进程可以有多个线程的 在不同的线程里面 只有1个对象)
多例 vs 单例
- 饿汉模式 (没有线程安全问题 )
//1.将构造变成private修饰
//2.提供静态成员变量 并初始化对象
//3.提供静态的方法 直接返回对象
public class UserInfo {
private UserInfo() {
}
private static UserInfo userInfo = new UserInfo();
public static UserInfo getInstance() {
return userInfo;
}
}
//弊端: 没有体现懒加载思想(想什么时候用就什么时候去创建)
//类与对象: 对成员变量尽可能不要初始化
2.懒汉模式
//1.将构造变成private修饰
//2.提供静态成员变量
//3.提供静态的方法
public class UserInfo {
private UserInfo() {
}
private static UserInfo userInfo;//null
public static UserInfo getInstance() {
if (userInfo == null) {
userInfo = new UserInfo();
//什么时候需要 就什么时候出初始化 体现懒加载的思想 有可能会出现线程安全的问题
}
return userInfo;
}
}
Thread-1:com.javasm.singlton.UserInfo@62b7b91
Thread-0:com.javasm.singlton.UserInfo@22e7a307
Thread-3:com.javasm.singlton.UserInfo@22e7a307
解决方式1
同步方法: 能解决安全问题 性能很低
同步代码快:
public static UserInfo getInstance() {
synchronized (UserInfo.class) {
if (userInfo == null) {
userInfo = new UserInfo();
//什么时候需要 就什么时候出初始化
}
}
return userInfo;
}
解决方式2
double check lock DCL
public static UserInfo getInstance() {
if (userInfo == null) {//dcl
synchronized (UserInfo.class) {
if (userInfo == null) {
userInfo = new UserInfo();
//什么时候需要 就什么时候出初始化
}
}
}
return userInfo;
}
解决方式3:
DCL还是有弊端:
由于计算机内部具有指令重排特性: 提高程序效率 jvm也是具备特性
创建对象: 3步
1.分配空间 2ms
2.执行构造初始化成员变量 10ms
3.赋值 内存地址赋值给引用 1ms
一共需要13ms完成对象的创建:
只执行了: 1 3 3ms
2 用属性
SpringMVC Controller 单例: 属性必然要初始化
限制指令重排.
volatile 功能与synchronized相似 都是解决数据可见性问题的,
synchronized: 原子性 顺序性 可见性
volatile: 可见性 顺序性 不能保证原子性 i++; int temp = i temp=i+1; i = temp;
限制指令重排. 效率快
public class UserInfo {
private UserInfo() {
}
private volatile static UserInfo userInfo;//null
//10 个线程 都在第一个if
//1个线程 new
public static UserInfo getInstance() {
if (userInfo == null) {//dcl
synchronized (UserInfo.class) {
if (userInfo == null) {
userInfo = new UserInfo();
//什么时候需要 就什么时候出初始化
}
}
}
return userInfo;
}
}
机器码+汇编码
序列化
4. volatile
在多线程环境下,自定义一个id生成器: 用户的id 整型
public class IDGenerator {
private static int id;//0
public void idIncrease() {
id++;//线程安全
//3步来完成 9001
// int temp = id;
// temp = id+1;
// id = temp;
}
public int getId() {
return id;
}
}
public class IDGenerator {
// private static int id;//0
// AtomicInteger/AtomicLong
// private static AtomicInteger id = new AtomicInteger();
private static LongAdder id = new LongAdder();
//性能优于AtomicInteger/AtomicLong 减少乐观锁的重试次数
public void idIncrease() {
// id++;//线程安全
//3步来完成 9001
// int temp = id;
// temp = id+1;
// id = temp;
// id.incrementAndGet();
id.increment();
}
public int getId() {
return id.intValue();
}
}
public static void main(String[] args) {
IDGenerator idGenerator = new IDGenerator();
//数据分析
List<Thread> list = new ArrayList<>(50);
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(() -> {
for (int i1 = 0; i1 < 100; i1++) {
idGenerator.idIncrease();
}
});
list.add(thread);
}
list.forEach(thread -> thread.start());
list.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//让100个子线程执行完毕之后 在主线程里面拿到最终的id值
//等待着100个线程死亡之后 才允许main逻辑
System.out.println("main:" + idGenerator.getId());//10000
}
}
5.注解
注释: 阐释代码含义 给程序员
注解: 解释说明 给程序看的 程序解析注解 @解释名
作用: 使用框架集成开发的时候: 1. xml文件配置 2.注解开发
使用位置: 类上 接口上 方法 属性 形参
高内聚 低耦合
1.xml文件配置 耦合度比较低 几个框架 只需要几个xml就可以集成 容易维护
2.注解开发 效率高 耦合度高 不太容易维护 SpringBoot 全注解
5.1 内置注解
@SuppressWarnings("all")
public class Demo extends Object {
@Override
public String toString() {
return super.toString();
}
@Deprecated
public void a() {
}
public void b() {
List list = new ArrayList();
}
public void c() {
List list = new ArrayList();
}
}
5.2 元注解
对注解进行注解。(解释说明)
1. @Target 标识当前注解的使用位置
2. @Retention 标识注解在哪个范围内有效的
3. @Documented 当我们使用javadoc 注解也会出现的文档文件中
4. @inherited 标识子类集成父类的注解
5. @FunctionalInterface 函数式接口--->修饰接口
5.3 自定义注解
使用jdk提供的元注解定义注解
public @interface 注解名称{
//组成部分: (数据/参数类型)成员变量
//可以支持数据的数据类型:
//1.基本数据类型
//2.String
//3.Class
//4.枚举
//5.以上所有类型的数组
//6.注解类型(解释参数)
}
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
//如果一个注解里面 参数只有value 参数名称可以省略
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
//制定参数
int id() default 1000;
String name() default "无名氏";
String[] hobby() default {};
double score() default 100;
Class<?>[] clazz() default {Student.class,Object.class};
DayOfWeek day() default DayOfWeek.MONDAY;
}
5.4 使用注解
@MyAnnotation(id = 1001, hobby = {"code", "music", "game"}, score = 100, clazz = {Student.class})
public class Student {
@MyAnnotation
//不指定参数的数据 获取的全部都是默认值
public void info() {
}
}
6.反射
泛型: List 是否可以存储 String。 反射
注解: 获得参数的数据? 反射
反射是框架的灵魂。
java语言具有动态性。 java语言有反射机制
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
操作class文件组成部分的技术.
将我们整个类里面的组成部分封装成相对应类。
类属性--->Filed
类的方法--->Method
类的构造--->Constructor
类里面的注解--->Annotation
正常开发中: 创建一个新的对象 new 为何反射?
框架集成开发的时候: 动态的将前台页面的用户注册的信息 自动封装成一个用户对象? 反射
name=jim&pass=1234&phone=17365
// 参数名称==类里面的属性名称 private set注入 User user = 反射.new
6.1 操作属性
反射实现: 模拟前台页面数据提交到对象
name=jim&pass=1234&phone=17365
private static void demo1() {
//name=jim&pass=1234&phone=17365
String name = "jim";
String pass = "1234";
String phone = "17365";
int id = 1001;
//约定大于配置
Map<String, Object> params = new HashMap<>(16);
params.put("name", name);
params.put("pass", pass);
params.put("phone", phone);
params.put("id", id);
//数据自动注入对象中
//反射: 操作正在运行的类或者接口或者枚举类的class内容 Class类对象
try {
//1.获得Class类对象
Class<?> clazz = Class.forName("com.javasm.reflect.UserInfo");
//2.反射创建UserInfo对象(构造方法)--->无参构造
//2.1 调用Class类的方法 newInstance() --->无参构造 Constructor
UserInfo userInfo = (UserInfo) clazz.newInstance();
//3.属性赋值(直接通过属性/set方法(重点))--->set注入
//3.1 通过属性
// Field[] fields = clazz.getFields();//获得public修饰的属性
// System.out.println(Arrays.toString(fields));//[]
// fields = clazz.getDeclaredFields();//类里面所有的属性
// System.out.println(Arrays.toString(fields));
// clazz.getDeclaredField(fieldName); 根据属性名称获得特定的属性
// clazz.getField(fieldName)
params.forEach((fieldName, fieldValue) -> {
try {
//根据属性名称获得特定属性
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);//开启权限访问
//对属性赋值 ---> 体现在userInfo对象里面
//public void set(Object obj, Object value)
field.set(userInfo, fieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
});
System.out.println(userInfo);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
6.2 操作方法
6.3 操作构造
//2.获得UserInfo的对象
// Constructor<?>[] constructors = aClass.getConstructors();//只能获取public修饰的构造方法
// System.out.println(Arrays.toString(constructors));
// Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();//类里面所有的构造方法
// System.out.println(Arrays.toString(declaredConstructors));
//通过有参创建对象
//public Constructor<T> getConstructor(Class<?>... parameterTypes) 有参构造方法的参数类型
Constructor<?> constructor = aClass.getConstructor(Integer.class, String.class, String.class, String.class);
UserInfo userInfo =(UserInfo) constructor.newInstance(1, "admin", "1111", "232334");
System.out.println(userInfo);
//new clone 序列化 反射(Class.newInstance/Constructor.newInstance)
6.4 操作注解
昨天 泛型 接口 获得某个城市天气数据 http://t.weather.itboy.net/api/weather/city
http://t.weather.itboy.net/api/weather/city == 后台写的一个方法 (映射出来了一个路径)
public static void main(String[] args) {
//注解在哪个类
//注解在哪个类哪个方法上
try {
Class<?> clazz = Class.forName("com.javasm.reflect.UserController");
PathAnno annotation1 = clazz.getAnnotation(PathAnno.class);
System.out.println("annotation1:"+annotation1.value());
Method method = clazz.getMethod("selectAllUser");
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof PathAnno) {
PathAnno pathAnno = (PathAnno) annotation;
String value = pathAnno.value();
System.out.println(value);
} else if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println(myAnnotation.id());
System.out.println(myAnnotation.name());
System.out.println(myAnnotation.day());
System.out.println(myAnnotation.score());
System.out.println(Arrays.toString(myAnnotation.clazz()));
System.out.println(Arrays.toString(myAnnotation.hobby()));
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
6.5 泛型擦除
public static void main(String[] args) {
//List<Integer> 是否可以存储 String。 反射
List<Integer> list = new ArrayList<>(10);
list.add(10);
//编译期间有效 运行期间: 存储的数据 Object
// list.add("abc");
// add() ---> Method--->invoke
Class<List> listClass = List.class;
try {
Method addMethod = listClass.getMethod("add", Object.class);
addMethod.invoke(list, "hello");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("list:" + list);
}