下面验证当catch/finally代码块同时存在return语句时,返回哪个
TestException.java代码:
public class TestException extends Exception {
public TestException() {
System.out.println("Generate TestException");
}
}
Test.java代码:
public class Test {
public static void main(String[] args) {
System.out.println(test());
}
private static String test() {
try {
generateException();
} catch (TestException e) {
System.out.println("Execute code in catch");
return "Return code in catch";
} finally {
return "Return code in finally";
}
}
private static void generateException() throws TestException {
throw new TestException();
}
}
运行结果:
Generate TestException
Execute code in catch
Return code in finally
可见,如果有finally代码块,即使catch代码块执行,也不会返回,最终将前面的return语句覆盖掉,返回finally中的语句
查阅资料了解到,单例模式的8种写法关键在于保证高并发环境下的线程安全,相比之下,通过枚举实现单例模式写法更简洁,实现简单,而且由于JVM的保证,不用担心线程安全问题。
public enum SingletonEnum {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
查阅Enum.class源码可知,当枚举类中无自定义构造方法时,将自动调用以下构造方法:
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
当打印枚举中常量值时,会调用toString()方法打印枚举字符串
public String toString() {
return this.name;
}
Set<Integer> test = new HashSet<>();
System.out.println(test.add(null));
System.out.println(test.add(null));
输出结果:
true
false
表明Set中重复放入null时第一次添加成功,之后添加失败
Map<String,Integer> map = new HashMap<>();
System.out.println(map.put("test",1));
System.out.println(map.put(null,3));
System.out.println(map.put(null,null));
输出结果:
null
null
3
可见,HashMap键值可放入null,put()方法返回值为null或者value值,若加入成功,则返回null,加入失败则返回value。这里想起HashSet的add方法,查阅源码发现
public boolean add(E e) {
return this.map.put(e, PRESENT) == null;
}
HastSet的add方法底层运用的也是HashMap的put方法,返回值与null比较返回boolean值
1.初始化长度
查阅ArrayList.class源码中的构造方法一共有三种
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
transient Object[] elementData;
//构造方法1
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else {
if (initialCapacity != 0) {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
this.elementData = EMPTY_ELEMENTDATA;
}
}
//构造方法2
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//构造方法3
public ArrayList(Collection<? extends E> c) {
this.elementData = c.toArray();
if ((this.size = this.elementData.length) != 0) {
if (this.elementData.getClass() != Object[].class) {
this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
}
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
2.扩容机制
源码中扩容主要函数如下:
private int newCapacity(int minCapacity) {
int oldCapacity = this.elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(10, minCapacity);
} else if (minCapacity < 0) {
throw new OutOfMemoryError();
} else {
return minCapacity;
}
} else {
return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
}
}
新容量newCapacity为原有容量增加二分之一,然后判断新容量和所需最小容量大小,若此时新容量依然小于所需最小容量,分别判断:
TreeMap默认按key的自然序排列,以下分别实现按key排序与value并输出结果。按value排序大致思路为将TreeMap转换成List后通过比较器进行排序
public class Main {
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>();
treeMap.put("c", 2);
treeMap.put("d", 1);
treeMap.put("a", 4);
treeMap.put("b", 3);
System.out.println("按key排序:");
for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
Iterator<Map.Entry<String, Integer>> it = treeMap.entrySet().iterator();
List<Map.Entry<String, Integer>> list = new ArrayList<>();
while (it.hasNext()) {
list.add(it.next());
}
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
return e1.getValue() - e2.getValue();
}
});
System.out.println("按value排序:");
for (Map.Entry<String, Integer> entry : list) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
输出结果:
按key排序:
a 4
b 3
c 2
d 1
按value排序:
d 1
c 2
b 3
a 4
LinkedList源码中有如下声明:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
可见LinkedList实现了Deque接口,而继续深入发现:
public interface Deque<E> extends Queue<E>
说明LinkedList的一个实现
类型变量使用大写形式,且比较短。在Java库中,使用变量E表示集合的元素类型,K和V分别表示表的关键字与值的类型,T表示“任意类型”,需要时还可以用临近的字母U和S表示。
类型擦除会导致很多特性无法使用,解决办法是通过反射,绕过编译器对泛型的限制
List<String> list = new ArrayList<>();
list.add("test");
System.out.println(list.get(0).getClass() instanceof String);
最后一行报错
Inconvertible types;cannot cast 'java.lang.Class>' to 'java.lang.String'
public class MyException<T> extends Throwable {}
报错信息:
Generic class may not extend 'java.lang.Throwable'
以下是查阅到的原因:来自stackoverflow
Both SomeException and SomeException are erased to the same type, there is no way for the JVM to distinguish the exception instances, and therefore no way to tell which catch block should be executed.