2、Java基础知识
→ 泛型
泛型与继承、类型擦除、泛型中 KTVE ? object 等的含义、泛型各种用法
泛型与继承:泛型是参数化类型,把运行时期可能产生的问题,提前到了编译时期,用来保证代码安全性。父类为泛型,子类继承时:范围大于或等于。
类型擦除: Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。 如在代码中定义List< Object>和List< String>等类型,在编译后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM是看不到的。
常见的类型参数:
- T 代表一般的任何类。
- E 代表 Element 的意思,或者 Exception 异常的意思。
- K 代表 Key 的意思。
- V 代表 Value 的意思,通常与 K 一起配合使用。
- ?通配符, 代表某种确定的类型,但是又有不确定性。 比如<? extends Collection> 不确定类型,确定实现了Collection接口。能确定上限,或确定下限。
- object:超类,需要强制类型转换,编译时可能类型不一致导致报错。
泛型的用法:泛型类、泛型接口、泛型方法
【参考链接】https://blog.csdn.net/briblue/article/details/76736356
限定通配符和非限定通配符、上下界限定符 extends 和 super
通配符有 3 种形式。
- <?>被称作无限定的通配符。
- <? extends T>被称作有上限的通配符。
- <? super T>被称作有下限的通配符。
List< Object> 、 List<?> 和原始类型 List 之间的区别?
原始List 没有类型限制,add 或者 get 的时候,接收或返回的对象类型是Object,所以在add时任何类型的对象均可,get时返回值类型为Object。List也没有赋值限定,即任何只要是集合类的对象均可,包括有类型限定的集合。
List<?>,即通配符类型,其引用变量,同样可以接受任何对应List的参数化类型,包括List,但是一旦赋值了,就只能remove、clear,不能add,保证了安全性和表述性。但不具有表述性,从中取出的元素时Object类型,要通过手动转换才能得到原本的类型。
List< Object> 有类型限制,类型限制为Object,但由于Object是所有类型的父类,所以在add时任何类型的对象均可,get时返回值类型也为Object。List< Object>也有赋值限定,只有类型是Object的集合对象才能赋值给List< Object>。
【参考链接】https://blog.csdn.net/qq_28411869/article/details/87880039
→ 反射
反射与工厂模式、反射的作用
反射机制: 反射机制是在运行(不是编译期)状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
jdk提供了三种方式获取一个对象的Class,就User user来说:
1.user.getClass(),这个是Object类里面的方法
2.User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类
3.Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类
反射机制的优缺点:优点是可以实现动态创建对象和编译,体现出很大的灵活性。缺点是对性能有影响。
工厂模式分为三种:
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
其中简单工厂模式是工厂方法模式的一种特例。
Class.forName(fullName).newInstance()
使用反射机制实现的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们可以使用属性文件配置所需要的子类。
反射的作用:
反编译:.class -> java
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
- 生成动态代理
Class 类、java.lang.reflect.*
在java.lang.reflect包中有三个类Field, Method, Contructor分别用于描述类的域, 方法和构造器
Field类中有一个getType方法,用来返回描述域所属类型的Class对象。
Method 和 Contructor 类有能够报告参数类型的方法,Method类还有一个可以报告返回类型的方法。
三个类都有一个叫做getModifiers的方法, 它将返回一个整形数值, 用不同的位开关描述public和static 这样的描述符的使用情况。
java.lang.reflect包中的Modifier类的静态方法分析getModifiers()返回的整形数值。 例如,可以使用Modifier类中的isPublic、isPrivate、isFinal判断权限修饰符。
Class类中的getFields,getMethods和getContructors 方法将分别返回类提供的public域,方法,和构造器数组,其中包括超类的公有成员。
Class类的getDeclareFields、getDeclareMethods和getDeclareContructors 方法将分别返回类中声明的全部域、方法和构造器,其中包括私有的和受保护的成员,但不包括超类的成员。
【参考链接】https://blog.csdn.net/q5706503/article/details/84892959
→ 注解
元注解、自定义注解、注解与反射的结合
元注解:
元注解:
- Documented——指明拥有这个注解的元素可以被javadoc此类的工具文档化。这种类型应该用于注解那些影响客户使用带注释的元素声明的类型。如果一种声明使用Documented进行注解,这种类型的注解被作为被标注的程序成员的公共API 。
- Inherited——指明该注解类型被自动继承。如果用户在当前类中查询这个元注解类型并且当前类的声明中不包含这个元注解类型,那么也将自动查询当前类的父类是否存在Inherited元注解,这个动作将被重复执行知道这个标注类型被找到,或者是查询到顶层的父类。
- Retention——指明在什么级别显示此注解
- Target——指明该类型的注解可以注解的程序元素的范围
Target主要的参数类型包括以下几种
- ElementType.TYPE 用于类,接口,枚举但不能是注解
- ElementType.FIELD 作用于字段,包含枚举值
- ElementType.METHOD 作用于方法,不包含构造方法
- ElementType.PARAMETER 作用于方法的参数
- ElementType.CONSTRUCTOR 作用于构造方法
- ElementType.LOCAL_VERIABLE 作用于本地变量或者catch语句
- ElementType.ANNOTATION_TYPE 作用于注解
- ElementType.PACKAGE 作用于包
Retention主要的参数类型包括以下几种
- RetentionPolicy.SOURCE 注解存在于源代码中,编译时会被抛弃
- RetentionPolicy.CLASS 注解会被编译到class文件中,但是JVM会忽略
- RetentionPolicy.RUNTIME JVM会读取注解,同时会保存到class文件中
自定义注解:
注解其实就是一种标记,可以在程序代码中的关键节点(类、方法、变量、参数、包)上打上这些标记,然后程序在编译时或运行时可以检测到这些标记从而执行一些特殊操作。
- 一,定义注解——相当于定义标记; 定义一个@interface类型,加上元注解,定义属性
- 二,配置注解——把标记打在需要用到的程序代码中;
- 三,定义AOP,解析注解——在编译期或运行期利用反射获取注解,并进行特殊操作。
注解与反射的结合 :
首先反射注解,那么保留策略必须是Runtime,也就是@Retention(RetentionPolicy.RUNTIME) 。在Java中,通过反射,我们可以知道每一个类的详细信息,比如有什么字段,有什么方法,类名等等,我们通过注解和反射配合,使用反射调用类中的方法,然后读取注解的参数来进行方法的执行。
Java常用注解
JDK自带注解有: @Override @Deprecated @Suppvisewarnings
Spring注解: @Repository @Service @Transactional @Controller @Component @Autowired @RequestMapping @ResponseBody @RequestParam @PathVariable @RequestBody @Method @Configuration @Scope @Lazy @PostConstruct @PreDestory @Qualifier @Resource @ModelAttribute @SessionAttributes @DependsOn @Primary @Async
Mybatis注解: @InsertProvider @DeleteProvider @UpdateProvider @SelectProvider @Options @Insert @Select @Update @Delete @Param @Result @Results
→ 序列化
什么是序列化与反序列化、为什么序列化、序列化底层原理、序列化与单例模式、protobuf、为什么说序列化并不安全
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。 发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。
序列化优点:
(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
(3)通过序列化在进程间传递对象;
底层原理:
1、JDK类库中序列化和反序列化API
(1)java.io.ObjectOutputStream:表示对象输出流。它的writeObject(Object obj)方法可以对参数指定的obj对 象进行序列化,把得到的字节序列写到一个目标输出流中;
(2)java.io.ObjectInputStream:表示对象输入流:它的readObject()方法源输入流中读取字节序列,再把它们 反序列化成为一个对象,并将其返回;
2、实现序列化的要求
只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常!
序列化与单例模式:
序列化会破坏单例模式, 因为序列化会通过反射调用无参数的构造方法创建一个新的对象。
ProtoBuf 是结构数据序列化 方法,可简单类比于 XML,其具有以下特点:
- 语言无关、平台无关。即 ProtoBuf 支持 Java、C++、Python 等多种语言,支持多个平台
- 高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单
- 扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序
protobuf 序列化后 生成 std::string 然后将std::string 转化为 QString 再反转回 std::string 进行反序列化 发现生成的值不对。
最常见的反序列化安全问题是通过修改序列化之后的数据字段, 抽象来看,只要是从Application之外读取或接收数据,并将其反序列化成Application或API中的对象,都可能存在反序列化安全问题。
【相关链接】https://blog.csdn.net/Roger_CoderLife/article/details/86704380
https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html
→ 正则表达式
java.lang.util.regex.*
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
→ 常用的 Java 工具库
commons.lang3、commons.*…、 guava-libraries、 netty
commons-lang3: StringUtils
common-beanutils: BeanUtils
commons-io: IOUtils
Guava-Libraries是google对java的一个扩展,主要涵盖集合、缓存、并发、I/O、反射等等。
netty参考: https://www.cnblogs.com/imstudy/p/9908791.html