java中的length和length()
为什么数组有length属性
- 数组是一个容器对象,包含固定数量的同一类型的值。一旦被创建,它的长度就是固定的。数组的长度可以做为final实力变量的长度,因此,长度可以被视为一个数组的属性。
- 创建数组的方法:通过数组表达式创建数组、通过初始化值创建数组
int [][] arr= new int[3][];
int [] arr= {1,2,3};
java中为什么没有定义一个类似String一样Array类
因为数组也是对象,下面的代码是合法的:
Object obj= new int[10];
因为数组中是内建类型,没有实际的类与它对应。如果存在一个Array类,它仍然需要一个数组来存放所有的数组元素。
为什么String有length()方法
String背后的数据结构以一个char数据value。
java中的equals()和hashcode()之间的关系
equals和hashcode都是Object里的方法。
hashcode和equals的约定关系如下:
- 如果两个对象相等,那么他们一定有相同的哈希值
- 如果两个对象的哈希值相同,那么这两个对象有可能相等也有可能不相等。(需要再通过equals方法来判断)
Map的底层数据结构是一个数组的数组(链表+数组),第一个数组的索引值是key的哈希码,通过这个索引可以定位到第二个数组。第二个数组可以 通过使用equals发昂发进行现行搜索的方式来查找对象。
注:equals方法是根据对象的特征进行重写的,比较的是两个对象的value值,如果不重写,则默认比较对象的引用地址。
hashcode方法默认实现会为每个对象返回一个不同的int类型的值。
- 如果equals方法重写了,但hashcode方法没重写,根据两者的关系
- 首先判断hash值,若相等,在进行equals方法比较进行验证
- 倘若哈希值不等,equals就没有判断的必要了
- 如果hashcode没有重写,那么必然返回两个不同的int值,这equals方法就没有用了。
java中的Comparable和Comparator
Comparable和Comparator都是java核心API提供的两个接口。他们是用来做对象比较的。
Comparable
- 实现了comparable接口的类,也就是说它的实例之间相互直接可以进行比较。但要实现compareTo()方法。 一般适用于可以修改原有类的情况。因为compareTo方法只要一个,无法实现多种比较。
Comparator
- 使用该接口,可以针对其中的特定的属性/字段进行比较。比如,当我们要比较两个人的时候,我可能通过年龄比较、也可能通过身高比较。
- 需要实现方法:compare()
- Comparator通常用于排序,Java中的Collections和Arrays中都包含排序的sort方法,该方法可以接收一个Comparator的实例(比较器)来进行排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class HDTV {
private int size;
private String brand;
public HDTV(int size, String brand) {
this.size = size;
this.brand = brand;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
class SizeComparator implements Comparator<HDTV> {
@Override
public int compare(HDTV tv1, HDTV tv2) {
int tv1Size = tv1.getSize();
int tv2Size = tv2.getSize();
if (tv1Size > tv2Size) {
return 1;
} else if (tv1Size < tv2Size) {
return -1;
} else {
return 0;
}
}
}
public class Main {
public static void main(String[] args) {
HDTV tv1 = new HDTV(55, "Samsung");
HDTV tv2 = new HDTV(60, "Sony");
HDTV tv3 = new HDTV(42, "Panasonic");
ArrayList<HDTV> al = new ArrayList<HDTV>();
al.add(tv1);
al.add(tv2);
al.add(tv3);
Collections.sort(al, new SizeComparator());
for (HDTV a : al) {
System.out.println(a.getBrand());
}
}
}
初始化特定的数据结构,常见的有可排序的Set(TreeSet)和可排序的Map(TreeMap)
想要使得TreeSet和TreeMap可排序,两个方法如下:
- 把实现Comparator的类的实例作为比较器,作为参数传入到TreeSet的声明里
- 存储的类实现Comparable接口
class Dog {
int size;
Dog(int s) {
size = s;
}
}
class SizeComparator implements Comparator<Dog> {
@Override
public int compare(Dog d1, Dog d2) {
return d1.size - d2.size;
}
}
public class ImpComparable {
public static void main(String[] args) {
TreeSet<Dog> d = new TreeSet<Dog>(new SizeComparator()); // pass comparator
d.add(new Dog(1));
d.add(new Dog(2));
d.add(new Dog(1));
}
}
class Dog implements Comparable<Dog>{
int size;
Dog(int s) {
size = s;
}
@Override
public int compareTo(Dog o) {
return o.size - this.size;
}
}
public class ImpComparable {
public static void main(String[] args) {
TreeSet<Dog> d = new TreeSet<Dog>();
d.add(new Dog(1));
d.add(new Dog(2));
d.add(new Dog(1));
}
}
重写VS重载
重载是,函数或方法哟相同的名称,但参数列表不相同的情况
重写是,Java的父类和子类中各有两个名称、参数列表都相同的方法的情况。子类中的新方法会覆盖附列中原有的方法。
- 重载是编译期概念,重写是运行时概念
- 重载就是静态分派,在编译时,根据静态类型和参数来判断调用那个方——静态多分派
- 重写就是动态分派,在运行时,根据实际类型来调用方法——动态单分派
- 静态分派和动态分派都不是二选一的排他关系,它们是在不同层次上筛选、确定目标方法的过程