ARTS 打卡(20.07.20-20.07.26)

用户头像
小王同学
关注
发布于: 2020 年 08 月 09 日



Algorithm:

leetcode 第10题 Regular Expression Matching  

动态规划解法:

public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] f = new boolean[m + 1][n + 1];
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
f[i][j] = f[i][j - 2];
if (matches(s, p, i, j - 1)) {
f[i][j] = f[i][j] || f[i - 1][j];
}
}
else {
if (matches(s, p, i, j)) {
f[i][j] = f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
public boolean matches(String s, String p, int i, int j) {
if (i == 0) {
return false;
}
if (p.charAt(j - 1) == '.') {
return true;
}
return s.charAt(i - 1) == p.charAt(j - 1);
}



Review:

Effective Java(第三版)英文版

Item1:

考虑静态工厂方法替代构造器

优点:

1:当一个类有多个构造函数时,我们无法很快速的区分出不同构造参数列表的构造器所代表的语义,我们可以通过命名更据意义的静态工厂方法来获取对象实例。

2:静态工厂方法每次调用都不是必须要重新实例化对象,可以返回第一次调用时已经实例化好的对象,实现了单例模式,也可以提升程序性能。

3:静态工厂方法可以返回当前对象的任何子对象,提高了灵活性,此种方式的一个应用是可以在不公开类的情况下,返回该类的对象,这种隐藏实现的方式可以使你的API相当紧凑(very compact)。这种技术适用于基于接口的框架,其中接口为静态工厂方法提供了自然返回类型。如: Collections.java

4:作为输入参数的函数,返回对象可以随着输入参数的变化进而返回不同的当前对象的子对象,比如说java原生的EnumSet类就是如此,EnumSet没有公共的构造函数,只有静态工厂方法of() (调用noneof()),在OpenJdk实现中,在noneof()方法中,如果参数长度小于等于64,则返回一个RegularEnumSet对象,如果大于64就返回JumboEnumSet

5:编写方法类时,返回对象所对应的类不需要存在,比如JDBC。静态方法时构成服务提供框架的基础,服务提供框架是提供者实现服务的系统,使客户端可以使用实现,将客户端与服务实现解耦。



短语:

lends itself to 有助于

prior to 在...之前

by convention 按照惯例



Tip:

java泛型的逆变与协变

先从数组开始:

public class Fruit {
public void type() {
System.out.println("fruit...");
}
}
public class Apple extends Fruit {
public void type() {
System.out.println("apple...");
}
}
public class Jonathan extends Apple {
}
public class Orange extends Fruit {
}
public class Generic{
public static void main(String[] args) {
Fruit[] fruit = new Apple[10];
fruit[0] = new Apple(); //编译通过 运行也没问题
fruit[1] = new Jonathan(); //编译通过 运行也没问题
fruit[2] = new Fruit(); //编译通过 运行时会抛出异常
}
}

1、java中数组是可协变的,所以Fruit数组可以指向Apple数组,这仅仅是在编译期,当程序开始运行,jvm确定fruit是一个Apple类型的数组,所以fruit[2] = new Fruit();会抛异常。



使用List时:

List<Fruit> fruit = new ArrayList<Apple>(); //编译报错

Apple的List并不是Fruit的List的子类型,也就是说两者没有任何关系。

泛型通过引入通配符的概念并重用extends关键字来实现泛型的协变。

List<? extends Fruit> fruit = new ArrayList<Apple>(); //编译通过
fruit.get(0).type(); //OK
fruit.add(new Fruit()); // ERROR: capture of ? extends Fruit

? extends Fruit表示一种宽泛的不确定的类型,它表示了任意的Fruit和Fruit的子类型,我们查看List中add的源码,add中接收的参数是一个 E e,可以认为要求是一个确定的类型,向上述代码中add的方式,可以理解为将? extends Fruit 这个不确定的参数传递进去了,这当然是不妥的,但是我们却可以调用Fruit中自定义的type方法,虽然? extends Fruit是一个不确定的类型,但是我们可以得知它最起码具备Fruit的特性,既Fruit是? extends Fruit类型的上限。



泛型逆变:

List<? super Apple> apple = new ArrayList<Fruit>();
apple.add(new Apple());
apple.add(new Jonathan());



如上例所示,apple可以指向任何Apple的父类List,也就是说? super Apple代表任何一个Apple父类List的引用,如apple = new ArrayList<Object>();这种写法也是OK的。这种表达方式使编译器知晓容器中的元素是Apple或是其Apple的子类。这样我就可以执行添加操作,但是无法调用apple中的type方法了,因为? super Apple表示的是Apple父类的list,这个父类无法被确定,Apple是它的一个下限。



参考资料《Java编程思想》

Share:

https://coolshell.cn/articles/11564.html《TCP/IP那些事儿(上)》

文章主要介绍了TCP为什么要三次握手和四次挥手,SYN ACK 以及TCPIP状态机、重传机制,SACK, D-SAKC等是如何解决数据丢失以及数据重复问题的,值得反复推敲。



用户头像

小王同学

关注

还未添加个人签名 2019.03.04 加入

还未添加个人简介

评论

发布
暂无评论
ARTS 打卡(20.07.20-20.07.26)