基本类型 | 大小 | 最小值 | 最大值 | 包装器类型 |
---|---|---|---|---|
boolean | —— | —— | —— | Boolean |
char | 16-bit | Unicode o | Unicode 2^16 | Character |
byte | 8-bit | -128 | +127 | Byte |
short | 16-bit | -2^15 | +2^15-1 | Short |
int | 32-bit | -2^31 | +2^31-1 | Integer |
long | 64-bit | -2^63 | +2^63-1 | Long |
float | 32-bit | IEEE754 | IEEE754 | Float |
double | 64-bit | IEEE754 | IEEE754 | Double |
void | —— | —— | —— | Void |
开始:2019年6月11日21:54:32,结束:2019年6月16日15:22:37
G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java>set CLASSPATH=C:\DOC\JavaT
G:\AndroidWorkspaces\Think4JavaExamples\app\src\main\java>echo %CLASSPATH%
C:\DOC\JavaT
开始:2019年6月16日15:23:28,结束:2019年7月13日16:44:09
开始:2019年7月13日16:44:09,结束:2019年7月14日14:48:12
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super sup = new Sub();
System.out.println("sup.field = " + sup.field +
", sup.getField() = " + sup.getField()); // 0,1
Sub sub = new Sub();
System.out.println("sub.field = " +
sub.field + ", sub.getField() = " +
sub.getField() +
", sub.getSuperField() = " +
sub.getSuperField()); //1,1,0
}
}
class Glyph {
void draw() {
System.out.println("Glyph.draw()");
}
Glyph() {
System.out.println("Glyph before draw()");
draw();
System.out.println("Glyph after draw()");
}
}
class RoundGlyph extends Glyph {
private int radius = 1;
RoundGlyph(int radius) {
this.radius = radius;
System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw() {
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
/*
输出结果:
Glyph before draw()
RoundGlyph.draw(), radius = 0
Glyph after draw()
RoundGlyph.RoundGlyph(), radius = 5
*/
```
开始:2019年7月15日11:40:33,结束:2019年7月21日11:49:27
interface X {
interface G {
void f();
}
// public 是多于的
public interface H {
void f();
}
void g();
// private 是不合法的
private interface I {
}
}
开始:2019年7月23日21:25:04,结束:2019年7月29日08:12:17
public class DotNew {
public class Inner {}
public static void main(String[] args) {
DotNew dotNew = new DotNew();
Inner inner = dotNew.new Inner();
}
}
```
public class Outer {
class Inner {
private int value = 11;
private void f() {
System.out.println("Inner.f()");
}
}
Inner inner() {
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.inner();
System.out.println(inner.value);
inner.f();
}
}
abstract class Base {
public Base(int i) {
System.out.println("Base constructor, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) { // 这个 i 不用是 final 的,因为它没有在匿名内部类内部被直接使用
return new Base(i) {
{
System.out.println("Inside instance initializer" + this);
}
@Override
public void f() {
System.out.println("In Anonymous f()");
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
/*
Base constructor, i = 47
Inside instance initializerinnerclasses.AnonymousConstructor$1@1540e19d
In Anonymous f()
*/
class MNA {
private void f() {
System.out.println("MNA.f()");
}
class A {
private void g() {
System.out.println("A.g()");
}
public class B {
void h() {
System.out.println("B.h()");
g();
f();
}
}
}
}
public class MutiNestingAccess {
public static void main(String[] args) {
MNA mna = new MNA();
MNA.A mnaa = mna.new A();
MNA.A.B mnaab = mnaa.new B();
mnaab.h();
}
}
/* 打印结果:
B.h()
A.g()
MNA.f()
*/
class D { }
abstract class E { }
class Z extends D {
E makeE() {
return new E() {};
}
}
public class MultiImplementation {
static void takesD(D d) {
}
static void takesE(E e) {
}
public static void main(String[] args) {
Z z = new Z();
takesD(z);
takesE(z.makeE());
}
}
/**
* 内部类的继承
* @author wzc
* @date 2019/7/28
*/
class WithInner {
class Inner {
}
}
public class InheritInner extends WithInner.Inner{
// InheritInner(){}
InheritInner(WithInner wi) {
wi.super();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
class Egg {
private Yolk y;
protected class Yolk {
public Yolk() {
System.out.println("Egg.Yolk");
}
}
public Egg() {
System.out.println("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk() {
System.out.println("BigEgg.Yolk()");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
/*
输出结果:
New Egg()
Egg.Yolk
*/
开始:2019年8月1日11:05:16,结束:2019年8月18日12:05:21
向上转型可以像作用于其他类型一样作用于泛型。
class GrannySmith extends Apple {}
class Gala extends Apple {}
class Fuji extends Apple {}
class Braeburn extends Apple {}
public class GenericsAndUpcasting {
public static void main(String[] args) {
ArrayList<Apple> apples = new ArrayList<Apple>();
apples.add(new GrannySmith());
apples.add(new Gala());
apples.add(new Fuji());
apples.add(new Braeburn());
for (Apple c : apples) {
System.out.println(c);
}
}
}
/**
* 打印结果:
* holding.GrannySmith@1540e19d
* holding.Gala@677327b6
* holding.Fuji@14ae5a5
* holding.Braeburn@7f31245a
*/
所有的 Collection 都可以用 foreach 语法遍历。因为 Collection 包含了这个接口:
Iterator<E> iterator();
Arrays.asList() 的输出,是一个 List,但是它的底层表示的是数组,因此不能调整尺寸。
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
list.set(1, 99); // 可以修改
// list.add(21); // 运行报错:UnsupportedOperationException,底层数组不支持增删
// list.remove(16);// 运行报错:UnsupportedOperationException,底层数组不支持增删
显式类型参数说明
class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}
public class AsListInterface {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(
new Crusty(), new Slush(), new Powder()
);
// 编译错误:需要 List,但发现 List
// List snow2 = Arrays.asList(
// new Light(), new Heavy()
// );
List<Snow> snow3 = new ArrayList<>();
Collections.addAll(snow3, new Light(), new Heavy());
// 显式地类型参数说明
List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy());
}
}
因为 Arrays.asList 是一个泛型函数,static 后面的
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
容器的打印:打印数组需要借助 Arrays.toString(),而打印容器无需任何帮助。这是因为已经重写了 toString() 方法。例如 List,Set 继承于 AbstractCollection 对 toString() 做了重写,Map 继承于 AbstractMap 对 toString() 做了重写。
List 的特点:可以将元素维护在特定的序列中。List 接口在 Collection 接口上增加了与索引相关的操作,例如:
boolean addAll(int index, Collection<? extends E> c);
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
// 迭代器
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
有两种类型的 List:ArrayList长于随机访问元素,但在List的中间插入和移除元素时较慢;LinkedList在List中间插入和删除代价较低,但在随机访问方面较慢。LinkedList的特性集比ArrayList更大。
对于 Collection 接口的 boolean containsAll(Collection> c) 方法来说,传入集合的元素顺序是不重要的,因为它在 AbstractCollection 中的实现是这样的:
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
List 的 List
接口:从较大的列表中创建出一个片段,这个产生的列表的幕后就是那个大的列表,因此,对返回的列表的修改都会反映到较大的列表中,反之亦然。查看这个方法在 ArrayList 中的实现:
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
可以看到返回的是一个 SubList 对象,它是 ArrayList 的内部类,继承于 AbstractList。
List 的 boolean retainAll(Collection> c),是继承自 Collection 接口的。这是一种有效的“交集”操作。
Collection 的两个重载的 toArray 方法有什么区别:
Object[] toArray();
<T> T[] toArray(T[] a);
第一个将任意的 Collection 转换成一个数组,返回的是 Object 数组;
第二个可以传递目标类型的数据,那么就会返回目标类型的数组。需要注意的是参数列表的参数传入:如果传入的参数数组太小,存放不下集合中所有的元素,那么 toArray 方法将创建一个具有合适尺寸的数组。如果传入的参数数组太大,那么下表为[list.size()] 的数组元素将会被置为 null,其他数组元素保持原值。所以我们最好将参数组大小定义与集合元素个数一致。这一点阿里巴巴Java开发手册上有强制要求。
持有事物是容器的基本工作。
Iterator
的真正威力:能够将遍历序列的操作与序列底层的结构分离。所以可以说,迭代器统一了对容器的访问。
ListIterator:是 Iterator 的子类型,但比 Iterator 更强大,它只能用于各种 List 类的访问。Iterator 只能向前移动,但是 ListIterator 可以双向移动。它可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用 set() 方法替换它访问过的最后一个元素。通过调用 listIterator() 方法产生一个指向 List 开始处的 ListIterator,并且还可以使用 listIterator(n) 方法创建一个一开始就指向列表索引为 n 的元素处的 ListIterator。需要注意的是若反向遍历,那么 n 应该指定为集合的size。
public interface ListIterator<E> extends Iterator<E> {
// Query Operations
boolean hasNext(); // 继承而来
E next(); // 继承而来
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
// Modification Operations
void remove(); // 继承而来
void set(E e);
void add(E e);
}
创建一个空的 LinkedList
,通过使用 ListIterator
,将若干个 Integer
出入这个 List
中,插入时,总是将它们插入到 List
的中间。
public class Ex14 {
private static void addMiddle(LinkedList<Integer> l, Integer[] ia) {
for (Integer i : ia) {
ListIterator<Integer> it = l.listIterator(l.size() / 2);
it.add(i);
System.out.println(l);
}
}
public static void main(String[] args) {
LinkedList<Integer> li = new LinkedList<>();
Integer[] x = {0, 1, 2, 3, 4, 5, 6, 7};
Ex14.addMiddle(li, x);
}
}
使用 LinkedList,可以产生更好的 Stack。
public class Stack<T> {
private LinkedList<T> storage = new LinkedList<>();
// 入栈
public void push(T t) {
storage.addFirst(t);
}
// 获取栈顶元素
public T peek() {
return storage.getFirst();
}
// 移除并返回栈顶元素
public T pop() {
return storage.removeFirst();
}
// 判断栈是否为空
public boolean empty() {
return storage.isEmpty();
}
@Override
public String toString() {
return storage.toString();
}
}
Set 具有与 Collection 完全一样的接口,因此没有任何额外的功能。实际上 Set 就是 Collection,只是行为不同。(这是继承与多态思想的简单应用:表现不同的行为。)
Queue:队列,是一种典型的先进先出(FIFO)的容器。它的特点是:从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的。
PriorityQueue:优先级队列,声明下一个弹出元素时最需要的元素。
Foreach:任何实现了 Iterable 接口的类,都可以将它用于 foreach 语句中。JavaSE5引入了 Iterable 接口,该接口包含一个能够产生 Iterator 的 iterator 方法,并且 Iterable 接口被 foreach 用来在序列中移动。
数组并不是一个 Iterable,但是 foreach 可以用于数组。
Arrays.asList():这个方法产生的 List 被直接打乱,会修改底层的数组。这个方法产生的 List 不支持增删。如果不想底层数组改变,就应该去创建一个副本的集合。
public class ModifyingArraysAsList {
public static void main(String[] args) {
Random random = new Random(47);
Integer[] integers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Integer> list = new ArrayList<>(Arrays.asList(integers));
System.out.println("Before shuffling: " + list);
Collections.shuffle(list, random);
System.out.println("After shuffling: " + list);
System.out.println("array: " + Arrays.toString(integers));
List<Integer> list2 = Arrays.asList(integers);
System.out.println("Before shuffling: " + list2);
Collections.shuffle(list2, random);
System.out.println("After shuffling: " + list2);
System.out.println("array: " + Arrays.toString(integers));
// list2.remove(0); // 不支持移除
// System.out.println("remove: " + list2);
// list2.add(5); // 不支持添加
}
}
/*
Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
After shuffling: [4, 6, 3, 1, 8, 7, 2, 5, 10, 9]
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Before shuffling: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
After shuffling: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8]
array: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8]
*/
数组一旦生成,它的容量就不能改变了。而 Collection,Map 却可以改变 size。
各种 Queue 及栈的行为,由 LinkedList 提供支持。
开始:2019年8月20日21:49:33,结束:2019年9月1日15:06:57
public class ExceptionSilencer {
public static void main(String[] args) {
try {
throw new RuntimeException();
} finally {
return;
}
}
}
public class Immutable {
public static String upcase(String s) {
System.out.println("s hashCode="+s.hashCode());
return s.toUpperCase();
}
public static void main(String[] args) {
String q = "howdy";
System.out.println("q hashCode="+q.hashCode());
System.out.println(q);
String qq = upcase(q);
System.out.println(qq);
System.out.println(q);
}
}
/*
打印结果:
q hashCode=99470565
howdy
s hashCode=99470565
HOWDY
howdy
*/
public class WhitherStringBuilder {
public String implicit(String[] fields) {
String result = "";
for (int i = 0; i < fields.length; i++) {
// 这里会生成多个 StringBuilder 对象:每循环依次就会创建一个。
result += fields[i];
}
return result;
}
public String explicit(String[] fields) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < fields.length; i++) {
result.append(fields[i]);
}
return result.toString();
}
}
可以使用 javap -c WhitherStringBuilder 反编译查看,其中 -c 表示将生成JVM字节码。开始:2019年12月8日19:14:55 结束:2020年1月18日21:45:16
public class Pair<F, S> {
// 注意这里是 public final 修饰的
public final F first;
public final S second;
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) {
return false;
}
Pair<?, ?> p = (Pair<?, ?>) o;
return Objects.equals(p.first, first) && Objects.equals(p.second, second);
}
@Override
public int hashCode() {
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
}
@Override
public String toString() {
return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
}
public static <A, B> Pair <A, B> create(A a, B b) {
return new Pair<A, B>(a, b);
}
}
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}
输出结果:true
声明 T
必须具有类型 Bounds
或者从 Bounds
导出的类型。T
擦除到了 Bounds
,就好像在类的声明中用 Bounds
替换了 T
一样。public class NonCovariantGenerics {
public static void main(String[] args) {
// 把数组的实现
// Fruit[] fruit = new Apple[10];
// 改为 泛型容器的实现,可以看到直接编译不通过了:类型不兼容:需要是List,但发现的却是ArrayList
// 理解为:不能把一个涉及 Apple 的泛型赋给一个涉及 Fruit 的泛型。
// List flist = new ArrayList();
// Apple 的 List 可以持有 Apple 类型及其子类型
List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
apples.add(new Jonathan());
// Fruit 的 List 可以持有 Fruit 类型及其子类型
List<Fruit> fruits = new ArrayList<>();
fruits.add(new Fruit());
fruits.add(new Jonathan());
fruits.add(new Apple());
fruits.add(new Orange());
// Apple 的 List 在类型上不等价于 Fruit 的 List。
}
}
开始:2020年1月19日22:05:17,结束:2020年2月19日23:41:56
Arrays.deepToString(Object[] a)
。Arrays.fill()
方法: 使用单一的值来填充整个数组或者数组的某个区域。System.arraycopy()
不会执行自动包装和自动拆包,两个数组必须具有相同的确切类型。(p776)开始: 2020年04月13日12:51:44, 结束:
Java SE5 内置的三种标准注解,是定义在 java.lang
中的注解:@Override
、@Deprecated
、@SuprressWarnings
。
注解的定义看起来很像接口的定义。与其他任何Java接口一样,注解也将会编译成class文件。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
interface
关键字前面有一个 @
。
@Target
定义你的注解将应用于什么地方,是一个方法还是一个域;
@Retention
用来定义该注解在哪一个级别可用,在源代码中(SOURCE
)、在类文件中(CLASS
)或者运行时(RUNTIME
)。
没有元素的注解称为标记注解(marker annotation),例如 @Test
。
注解的元素在使用时表现为名-值对的形式,并需要置于注解声明之后的括号内。
Java 提供了四种注解,专门负责新注解的创建。这四种注解被称为元注解,因为它们专职负责注解其他的注解。
@Target
:表示该注解可以用于什么地方。可能的 ElementType 参数包括:
CONSTRUCTOR
:构造器的声明
FIELD
:域声明(包括 enum
实例)
LOCAL_VARIABLE
:局部变量声明
METHOD
:方法声明
PACKAGE
:包声明
PARAMETER
:参数声明
TYPE
:类、接口(包括注解类型)或 enum
声明
@Retention
:表示需要在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:
SOURCE
:注解将被编译器丢弃;
CLASS
:注解在 class 文件中可用,但会被 VM 丢弃;
RUNTIME
:VM 将在运行期也保留注解,因此也可以通过反射机制读取注解的信息。
@Documented
:将此注解包含在 Javadoc 中。
@Inherited
:允许子类继承父类中的注解。
Class
、Constructor
、Method
和 Field
等类都实现了 AnnotatedElement
接口。
注解元素可用的类型:
所有基本类型(int
,float
,boolean
等)
String
Class
enum
Annotation
以上类型的数组
注意:如果使用了其他类型,那么编译器就会报错。也不允许使用任何包装类型。
注解可以作为元素的类型,也就是说注解可以嵌套。
默认值限制
元素不能有不确定的值:要么有默认值,要么在使用注解时提供元素的值。
对于非基本类型的元素,不管是在源代码中声明时,还是在注解接口中定义默认值时,都不能以 null 作其值。
快捷方式:如果程序员的注解中定义了名为value的元素,并且在应用注解的时候,如果该元素是唯一需要赋值的一个元素,那么此时无需使用名-值对的这种语法,而只需要在括号内给出 value 元素所需的值即可。
编译器允许程序员对同一个目标使用多个注解。注意,使用多个注解的时候,同一个注解不能重复使用。
注解不支持继承:不能使用关键字 extends
来继承某个 @interface
。
注解处理工具apt:是sun公司为了帮助注解的处理过程而提供的工具。与 javac 一样,apt 被设计为操作 Java 源文件,而不是编译后的类。