类名首字母大写 && 方法首字母小写 && 变量/方法名遵循驼峰命名
String
字符串final
修饰符,变量就变成了常量field:单个变量域,用private
修饰field,拒绝外部访问
方法名相同,但各自参数不同(返回值类型通常也相同)
目的是:功能类似的方法使用同一名字,更容易记住
子类定义了与父类方法签名完全相同的方法
Overload方法签名不同,是一个新方法;
Override方法签名相同,返回值也相同,是重定义父类的方法。
加上@Override可以让编译器帮助检查是否进行了正确的覆写。
希望进行覆写,但是不小心写错了方法签名,编译器会报错。
Java使用extends
关键字来实现继承
子类自动获得了父类的所有字段,严禁定义与父类重名的字段!
关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName
任何class的构造方法,第一行语句必须是调用父类的构造方法。
子类不会继承任何父类的构造方法。(子类默认的构造方法是编译器自动生成的。)
【 如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();
】
但是如果父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。
在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。
子类无法访问父类的private字段或者private方法。
把private改为protected。用protected
修饰的字段可以被子类访问
如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。
用final修饰的方法不能被Override,
用final修饰的类不能被继承,
用final修饰的字段在初始化后不能被修改
从Java 15开始,允许使用sealed修饰class,并通过permits明确写出能够从该class继承的子类名称。
public sealed class Shape permits Rect, Circle, Triangle {...}
这种sealed类主要用于一些框架,防止继承被滥用
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
功能:允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码
如果class定义了方法,但没有具体执行代码,这个方法就是抽象方法,用abstract
修饰。
因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。
我们无法实例化一个抽象类
编译器会告诉我们,无法编译,因为包含抽象方法。
抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
如果一个抽象类没有字段,全都是抽象方法,就可以把该抽象类改写为接口
( 所有方法默认都是public abstract )
当一个具体的class去实现一个interface时,需要使用implements
关键字
一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface
interface继承自interface使用extends
合理设计interface和abstract class的继承关系,可以充分复用代码。一般来说,公共逻辑适合放在abstract class中,具体逻辑放到各个子类,而接口层次代表抽象程度。
List list = new ArrayList(); // 用List接口引用具体子类的实例
Collection coll = list; // 向上转型为Collection接口
Iterable it = coll; // 向上转型为Iterable接口
目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。
可以把静态字段理解为描述class本身的字段(非实例字段)
调用实例方法必须通过一个实例变量,
而调用静态方法则不需要实例变量,通过类名就可以调用。
【 静态方法类似其它编程语言的函数。】
静态方法属于class而不属于实例
因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段。
通过实例变量也可以调用静态方法,但这只是编译器自动帮我们把实例改写成类名而已。
通常情况下,通过实例变量访问静态字段和静态方法,会得到一个编译警告。
因为interface是一个纯抽象类,所以它不能定义实例字段。但是,interface是可以有静态字段的,并且静态字段必须为final类型。
public interface Person {
// 编译器会自动加上public statc final:
int MALE = 1;
int FEMALE = 2;
}
泛型就是编写模板代码来适应任意类型(一套代码创建各种类型);
例如编写ArrayList<T>
,就可以创建任意类型的ArrayList
为用到的类创建对应的ArrayList<类型>
:
ArrayList<String> strList = new ArrayList<String>();
注意泛型的继承关系:可以把
ArrayList<Integer>
向上转型为List<Integer>
(T不能变!),但不能把ArrayList<Integer>
向上转型为ArrayList<Number>
(T不能变成父类)
<T>
不能是基本类型,例如int
Pair<String>.class;
Pair<Object>
x instanceof Pair<String>;
new T()
子类可以获取父类的泛型类型<T>
如果一个Java对象可以在内部持有若干其他Java对象,并对外提供访问接口,我们把这种Java对象称为集合。
Java标准库自带的java.util
包提供了集合类:Collection,它是除Map外所有其他集合类的根接口。
ArrayList
而不是LinkedList
;List.of()
List<Integer> list = List.of(1, 2, 5); //不接受null值
get(i)
不推荐 】boolean hasNext()
判断是否有下一个元素,E next()
返回下一个元素。List<String> list = List.of("apple", "pear", "banana");
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
System.out.println(s);
}
//简化
for (String s : list) {
System.out.println(s);
}
把List变为Array:
1️⃣ 调用toArray()方法直接返回一个Object[]数组
Object[] array = list.toArray(); //会丢失类型信息
2️⃣ 给toArray(T[])
传入一个类型相同的Array,List内部自动把元素复制到传入的Array中
Integer[] array = list.toArray(new Integer[list.size()]);
3️⃣ 通过List接口定义的T[] toArray(IntFunction<T[]> generator)方法:
Integer[] array = list.toArray(Integer[]::new);
把Array变为List:
1️⃣ 通过List.of(T…)方法最简单
Integer[] array = { 1, 2, 3 };
List<Integer> list = List.of(array);
( 返回的List不一定就是ArrayList或者LinkedList,因为List只是一个接口,List.of()返回的是一个只读List )
boolean contains(Object o)
int indexOf(Object o)
如果元素不存在,就返回-1contains()
、indexOf()
这些方法,需要实现equals()
方法:确定实例哪些字段相等,就认为实例相等Objects.equals()
比较,对基本类型直接用==
比较public boolean equals(Object o) {
if (o instanceof Person) {
Person p = (Person) o;
return Objects.equals(this.name, p.name) && this.age == p.age;
}
return false;
}
boolean add(E e)
boolean remove(Object e)
boolean contains(Object e)
put(K key, V value)
get(K key)
boolean containsKey(K key)
keySet()
for (String key : map.keySet()) {
Integer value = map.get(key);
System.out.println(key + " = " + value);
}
entrySet()
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " = " + value);
}
要正确使用HashMap
,作为key的类必须正确覆写equals()
和hashCode()
方法
equals()用到的用于比较的每一个字段,都必须在hashCode()中用于计算;
equals()中没有使用到的字段,绝不可放在hashCode()中计算。
int hashCode() {
return Objects.hash(firstName, lastName, age);
}
SortedMap
在遍历时严格按照Key的顺序遍历,最常用的实现类是TreeMap
;作为SortedMap的Key必须实现Comparable
接口,或者传入Comparator
;
Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
Java提供了标准的迭代器模型,即集合类实现java.util.Iterable
接口
for each
循环:List、Set和Queue会迭代每个元素,Map会迭代每个key
用 迭代器 Iterator 遍历:无需知道集合内部元素是按什么方式存储的
List<String> list = List.of("Apple", "Orange", "Pear");
for (String s : list) {
System.out.println(s);
}
实际编译:
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
System.out.println(s);
}
Collections类提供了一组工具方法来方便使用集合类
List<T> emptyList()
&& List<T> singletonList(T o)
Map<K, V> emptyMap()
&& Map<K, V> singletonMap(K key, V value)
Set<T> emptySet()
&& Set<T> singleton(T o)
返回的集合是不可变集合,无法向其中添加或删除元素
实际上,使用List.of(T...)
更方便,因为它既可以创建空集合,也可以创建单元素集合,还可以创建任意个元素的集合
List<T> unmodifiableList(List<? extends T> list)
break:跳出自己所在的那一层循环(一层)
continue: 提前结束本次循环,继续执行下次循环