本文主要包括:
- Java范型
Java范型
什么是范型?
泛型(generic)是指参数化类型的能力。可以定义带泛型类型的类或方法,随后编译器会用具体的类型来代替它。
为什么要用范型?
Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
- 类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。
- 消除强制类型转换。泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
- 潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
注意:
Point
遇到一个静态方法,使用如下范型:
static <T> WatermarkStrategy<T> forBoundedOutOfOrderness(Duration maxOutOfOrderness) {
return (ctx) -> new BoundedOutOfOrdernessWatermarks<>(maxOutOfOrderness);
}
这个方法的返回值是WatermarkStrategy<T>
,前面那个T,不知道是什么意思,在用的时候,使用如下方法:
stream.assignTimestampsAndWatermarks(WatermarkStrategy
.<Tuple2<String, Long>>forBoundedOutOfOrderness(Duration.ofSeconds(3))
.withIdleness(Duration.ofSeconds(5))
.withTimestampAssigner((event,timestamp) -> event.f1))
.keyBy(x -> x.f0)
.window(TumblingEventTimeWindows.of(Time.seconds(5)))
.apply(new WindowFunctionTest())
.print();
WatermarkStrategy.<Tuple2<String, Long>>
:因为这个方法是静态方法,所以可以直接类名.方法,后面的.<Tuple2<String, Long>>
就是方法里前面那个
Java的多态
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法
多态体现为父类引用变量可以指向子类对象。
前提条件:必须有子父类关系。
注意:在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
多态的定义与使用格式
定义格式:父类类型 变量名=new 子类类型();多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作。
多态成员变量:编译运行看左边
多态成员方法:编译看左边,运行看右边
多态的转型
多态的转型分为向上转型和向下转型两种
向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
public class Main {
public static void main(String[] args) {
// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
public Income(double income) {
this.income = income;
}
public double getTax() {
return income * 0.1; // 税率10%
}
}
class Salary extends Income {
public Salary(double income) {
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
样例2:
public class Test {
static void testDuo(Test1 t){
System.out.println("aa");
}
public static void main(String[] args) {
Test2 t1 = new Test2();
t1.test("bb");
testDuo(t1);
}
public interface Test1{
}
public static class Test2 implements Test1{
public void test(String str){
System.out.println(str);
}
}
}
这样做的好处是:
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
抽象类与接口
抽象类
在Java中被abstract关键字修饰的类称为抽象类,被abstract关键字修饰的方法称为抽象方法,抽象方法只有方法的声明,没有方法体。抽象类的特点:
- 抽象类不能被实例化只能被继承;
1.1 抽象类不能被实例化,所以抽象类必须被继承,才能被使用
1.2 抽象类可以和类一样,实现接口,但抽象类不需要实现接口下的所有方法
1.3 抽象类被子类继承以后,就会强迫子类充血抽象类中定义的抽象方法,除非子类也是抽象类 - 包含抽象方法的一定是抽象类,但是抽象类不一定含有抽象方法
- 抽象类中的抽象方法的修饰符只能是public或者protected,默认为default
- 抽象类可以包含属性、方法、构造方法,但是构造方法不能用于实例化,并且子类实例化以后,抽象类的构造方法一定会被调用
接口
Java中接口用interface关键字修饰,特点为:
- 接口可以包含变量、方法;变量被隐式的指定为 public stastic final,方法被隐式指定为public abstract
- 接口支持多继承,即一个接口可以extends多个接口,间接的解决了java中类的单继承问题
- 一个类可以实现多个接口
- JDK1.8中对接口增加了新的特性:
4.1 默认方法(default method):JDK 1.8允许给接口添加非抽象的方法实现,但必须使用default关键字修饰;定义了default的方法可以不被实现子类所实现,但只能被实现子类的对象调用;如果子类实现了多个接口,并且这些接口包含一样的默认方法,则子类必须重写默认方法;
4.2 静态方法(static method):JDK 1.8中允许使用static关键字修饰一个方法,并可以提供实现,称为接口静态方法。接口静态方法只能通过接口调用(接口名.静态方法名)。
总结:继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如狗是否能钻火圈,能则可以实现这个接口,不能就不实现这个接口。
Java常用的设计模式
单例模式
解决了什么痛点或有什么好处?
保证在Java应用程序中,一个类Class只有一个实例存在。 使用单例模式的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收
什么情况下使用单例模式?
第一、控制资源的使用,通过线程同步来控制资源的并发访问;
第二、控制实例产生的数量,达到节约资源的目的。
第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。
比如,数据库连接池的设计一般采用单例模式,数据库连接是一种数据库资源
策略模式
解决了什么痛点或有什么好处?
什么情况下使用策略模式?
工厂模式
mysql的jdbc
解决了什么痛点或有什么好处?
好处
将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,明确了职责。
把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则,面向接口编程,而不是面向实现编程。
缺点:
由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
要新增产品类的时候,就要修改工厂类的代码,违反了开放封闭原则(对扩展的开放,对修改的关闭)。
简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
什么情况下使用工厂模式?
观察者模式
kafka的发布订阅,其实就类似于这种观察者模式
解决了什么痛点或有什么好处?
什么情况下使用观察者模式?
JVM知识点总结
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。
一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处:))