文章目录
抽象类
如果一个类中没有足够的信息用来描述一个具体的对象,这样的类就是抽象类。
abstract class Shape{
public void draw(){
System.out.println("画图形!");
}
}
如果不想写draw()方法的方法体:
abstract class Shape{
public abstract void draw();
}
//如果这样写那么类名前的abstract修饰符不能省略,有抽象方法的类一定是抽象类
抽象方法没有方法体,抽象类中可以有普通类中的成员
abstract class Shape{
public static int a=10;
public abstract void draw();
public void func(){
}
}
抽象类的最大意义是被继承。
普通类继承抽象类,必须重写抽象类的抽象方法;抽象类A继承抽象类B则不强制要求A重写B中的抽象方法。
抽象方法不能是private,final,static。要满足重写的规则。
final和abstract是矛盾的。
抽象类中可以有构造方法。
可以实现多态
接口
接口是多个类的公共规范,是一种引用数据类型。
关键字:interface
接口中的方法不能有方法体,如果非要有具体实现,加default:
interface IShape{
public abstract void draw();
default public void func(){
}
}
可以实现多态
接口不能被实例化
一个接口就是一个java文件
因为接口的抽象方法是public修饰,所以子类重写时只能是public
接口中不能有静态代码块和构造方法
如果类没有实现接口中所有的抽象方法,则类必须被设置为抽象类
实现多个接口
一个类可以实现多个接口,可以解决多继承问题
interface IFlying{
void flying();
}
interface ISwimming{
void swimming();
}
interface IRunning{
void running();
}
class Animal{
public String name;
public int age;
public Animal(String name,int age){
this.name=name;
this.age=age;
}
public void eat(){
System.out.println("吃饭!");
}
}
class Duck extends Animal implements IFlying,IRunning,ISwimming{
public Duck(String name,int age){
super(name,age);
}
@Override
public void flying() {
System.out.println(name+"正在飞!");
}
@Override
public void swimming() {
System.out.println(name+"正在游泳!");
}
@Override
public void running() {
System.out.println(name+"正在跑!");
}
@Override
public void eat() {
System.out.println(name+"正在吃鸭粮!");
}
}
public class Test5 {
public static void walk(IRunning iRunning){
iRunning.running();
}
public static void eat(Animal animal){
animal.eat();
}
public static void main(String[] args) {
eat(new Duck("duck",2));
walk(new Duck("duck",2));
}
}
Object类
Object是所有类的父类,默认会继承Object类。
hashcode()
返回对象的哈希值
Person person1=new Person("张三",18);
Person person2=new Person("张三",18);
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
460141958
1163157884
hashCode()这个方法算了一个具体的对象位置
如果自己重写hashCode(),输出结果一样
@Override
public int hashCode() {
return Objects.hash(name,age);
}
24022538
24022538
equals()
class Person{
private String name ;
private int age ;
public Person(String name, int age) {
this.age = age ;
this.name = name ;
}
}
public class Test6 {
public static void main(String[] args) {
Person person1=new Person("张三",18);
Person person2=new Person("张三",18);
System.out.println(person1.equals(person2));
}
}
输出结果:
false
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false ;
} if(this == obj) {
return true ;
}
if (!(obj instanceof Person)) {
return false ;
}
Person per=(Person) obj;
if(this.name.equals(per.name)&&this.age== per.age){//字符串也是引用类型
return true;
}
return false;
}
我们可以重写一个equals(),让程序调用自己写的equals(),输出结果为true.
Object类里的equals()比较的是引用变量里存储的地址
写了自定义类型要重写equals()
接口使用示例
Comparable<>接口
import java.util.Arrays;
class Student{
public String name;
public int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("bit",10);
students[1]=new Student("hello",40);
students[2]=new Student("abc",5);
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
学生类有姓名,年龄。自定义类型需要自己指定比较的方法。
class Student implements Comparable<Student>{
让学生类继承一个接口,并重写接口里的方法
@Override
public int compareTo(Student o) {
if(this.age-o.age>0){
return 1;
}else if(this.age-o.age<0){
return -1;
}else{
return 0;
}
}
现在运行结果是:
[Student{name='abc', age=5}, Student{name='bit', age=10}, Student{name='hello', age=40}]
根据年龄排序
关于比较年龄,compareTo()方法的使用:
<Student>泛型
让 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法。在 sort 方法中会自动调用 compareTo 方法。
自定义类型比较大小,要让这个类具备可比较的功能,让这个类实现接口Comparable。
Comparator<>接口
实现另一种接口,Comparator<>:
“类优先原则”:一个类扩展了一个超类,同时实现了一个接口,并从超类和接口中继承了相同的方法,在这种情况下只会考虑超类的方法,接口无论是否提供默认方法都会被忽略。
class AgeComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;
}
}
class NameComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("bit",10);
students[1]=new Student("hello",40);
students[2]=new Student("gbc",5);
//AgeComparator ageComparator=new AgeComparator();
NameComparator nameComparator=new NameComparator();
Arrays.sort(students,nameComparator);
//Arrays.sort(students,ageComparator);
System.out.println(Arrays.toString(students));
}
输出结果
[Student{name='bit', age=10}, Student{name='gbc', age=5}, Student{name='hello', age=40}]
模拟实现冒泡排序
class Student implements Comparable<Student>{
public int compareTo(Student o) {
if(this.age-o.age>0){
return 1;
}else if(this.age-o.age<0){
return -1;
}else {
return 0;
}
}
}
public class Test {
public static void bubbleSort(Comparable[] array){
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1-i; j++) {
if(array[j].compareTo(array[j+1])>0){
Comparable tmp=array[j];
array[j]=array[j+1];
array[j+1]=tmp;
}
}
}
}
public static void main(String[] args) {
Student[] students=new Student[3];
students[0]=new Student("bit",10);
students[1]=new Student("hello",40);
students[2]=new Student("gbc",5);
bubbleSort(students);
System.out.println(Arrays.toString(students));
}
自定义的类排序首先要保证每个对象都是可比较的,implements Comparable所以实现接口。然后调用compareTo()方法挨个进行比较
Clonable 接口和深拷贝
如果我想克隆person这个对象,Object超类中有clone()这个方法,但是person不能调用。
那么要让person具有可克隆的能力
class Person implements Cloneable{
Object类不是抽象类,却能容纳抽象方法,其实就是native在起作用,被native关键字修饰的方法属于本地方法,表示Java的作用范围已经无法达到,底层会去调用C/C++的库。
clone()方法是Object里面的protected方法,只允许在同包和子类内部调用。现在有一个类Cat,默认继承Object,所以假如你的调用测试写在Cat类里面,那么是可以调用的。但是假如你在和Cat同包的下面写了一个Test测试类,并尝试在Test里面实例化Cat,并调用clone(),是无法调用的。
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
不同包中需要通过super去访问,当前类中必须重写clone方法
class Person implements Cloneable{
public int id;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();//调用Object的clone方法
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
public class Test2 {
public static void main(String[] args)throws CloneNotSupportedException {
Person person=new Person();
person.id=99;
Person person2=(Person) person.clone();
System.out.println(person);
System.out.println(person2);
}
}
Person{id=99}
Person{id=99}
浅拷贝
class Money{
public double m=12.5;
}
class Person implements Cloneable{
public int id;
public Money money=new Money();//组合
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
public class Test2 {
public static void main(String[] args)throws CloneNotSupportedException {
Person person=new Person();
Person person2=(Person) person.clone();
person2.money.m=1999;
System.out.println("person "+person.money.m);
System.out.println("person2 "+person2.money.m);
}
}
person 1999.0
person2 1999.0
person2.money.m=1999,把person2指向的m改了,person指向的m也改了,因为m只有一份m,person和person2指向的是同一份,这就是浅拷贝。
如果想把m也拷贝一份?
深拷贝
class Money implements Cloneable{
public double m=12.5;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public int id;
public Money money=new Money();
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();
Person tmp=(Person) super.clone();
tmp.money=(Money) this.money.clone();
return tmp;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
'}';
}
}
public class Test2 {
public static void main(String[] args)throws CloneNotSupportedException {
Person person=new Person();
Person person2=(Person) person.clone();
person2.money.m=1999;
System.out.println("person "+person.money.m);
System.out.println("person2 "+person2.money.m);
}
}
person 12.5
person2 1999.0
方法调用结束,tmp的值传给person2,tmp被销毁