文章目录
前言
一、抽象类
当一个类不能完整的描述具体的对象的时候,就叫抽象类。
抽象方法没有具体实现。
定义
abstract class Shape{//抽象类
public abstract void draw();//抽象方法
}
只要有抽象方法就必须定义为抽象类。抽象类中可以有普通的成员方法和成员变量。
注意:1.抽象类不能够实例化。普通类可。但是可以存在构造方法,子类实例化帮助其初始化。
2.抽象类不一定包含抽象方法。
3.当普通类继承抽象类,普通类必须重写抽象方法。(用alt+回车快捷重写)
4.抽象类存在的最大意义就是为了被继承。
5.当一个抽象类A继承一个抽象类B,此时抽象类A并不需要重写,但是当一个普通C继承了抽象A,此时需要重写所以没有重写的抽象方法。
6.抽象方法不能被final和static所修饰。
7.使之多一次编译器校验。
二、接口
对一个标准的规范。多个类的公共规范。
interface关键字。
interface Shape{
public abstract void draw();
}
1.接口是使用interface来定义的。
2.接口中不能有实现的方法,但是有两种类型的方法需要注意:
2.1静态方法可以有具体实现。
2.2有default关键字修饰的也可有具体实现。(jdk8以后)
3.接口中默认是public abstract修饰的方法。
5.里面的成员变量默认是public static final修饰的常量。
不赋值报错。赋值且为静态常量
上面与其等价。
6.接口不能通过new关键字实例化。
7.类和接口使用关键字implements来关联。抽象方法必须重写,default方法可以不重写,static方法不能重写。
8.虽然接口不能够实例化自己,但可以向上转型。如下还是ok的。接口被编译完后也有自己独立的.class文件。
9.创建接口时接口的命名一般以大写的I开头。(软规定)
10.子类实现接口的方法的时候,这个方法一定要是public修饰的。(因为接口默认public abstract)
11.接口当中不能有构造方法和代码块。
12.一个类不想实现接口中的方法被定义为抽象类。
接口案例
interface USB{
void close();
void open();
}
class Mouse implements USB{
@Override
public void open(){
System.out.println("打开鼠标");
}
@Override
public void close(){
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("点击鼠标");
}
}
class KeyBoard implements USB{
@Override
public void open(){
System.out.println("键盘打开");
}
@Override
public void close(){
System.out.println("键盘关闭");
}
public void input(){
System.out.println("键盘输入");
}
}
class Computer implements USB{
@Override
public void open(){
System.out.println("打开电脑");
}
@Override
public void close(){
System.out.println("关闭电脑");
}
public void diannao(){
System.out.println("打游戏");
}
public void useDevice(USB usb){//向上转型
usb.open();
if(usb instanceof KeyBoard){//向下转型,使用子类特有的方法
KeyBoard keyBoard=(KeyBoard) usb;
keyBoard.input();
}else if(usb instanceof Mouse){
Mouse mouse=(Mouse) usb;
mouse.click();
}
usb.close();
}
}
public class Test04 {
public static void main(String[] args) {
Computer computer=new Computer();
computer.useDevice(new Mouse());
Computer computer1=new Computer();
computer1.useDevice(new KeyBoard());
}
}
java不支持多继承。一个类实现多接口可以解决多继承的问题。
注意:一定是先继承类然后再实现接口。只能继承一个类。可以有多个接口。
为什么定义接口,因为在能满足类的需求。如飞接口,不是所有的动物都会飞,所以不定义在动物类中。单独定义类也不可,因为只能继承一个类。
接口的继承:extends来继承,意味拓展接口的功能。
抽象类和接口区别:
1.抽象类的类可以不是 public abstract修饰的,而接口必须是。
2.接口中只要static final修饰的常量,而抽象类中可以有成员变量。
3.抽象类是利用extends来继承。而接口是implements来重写。
4.定义抽象类是class abstract,而接口是interface.
5.抽象类只可以继承一个,而接口可以有多个。
6.抽象类中可以有构造方法,但接口不能有。
7.接口中的权限是public,抽象类中可以有各种权限。
三、自定义类型比较
compareTo(Comparable接口)
要把学生类强转为Comparable,然后调用compareTo。需要学生和comparable建立关系,这里利用接口。没有接口无法识别compareTo.
当我们对自定义类型进行比较一定实现可比较的接口。
import java.util.Arrays;
class Student implements Comparable<Student>{
public String name;
public int age;
public double score;
public Student(String name,int age,double score) {
this.name = name;
this.age=age;
this.score=score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
public int compareTo(Student o){//重写 //只能实现一个比较
return this.age-o.age;
}
}
public class Test02 {
public static void main1(String[] args) {
Student [] array=new Student[3];
array[0]=new Student("lili",34,89.2);
array[1]=new Student("huanghuang",33,90.2);
array[2]=new Student("zhangsan",21,22.2);
System.out.println("排序前"+ Arrays.toString(array));
Arrays.sort(array);//底层调用compareTo。因此要重写其方法。
System.out.println("排序后"+ Arrays.toString(array));
}
public static void main(String[] args) {
Student [] array=new Student[3];
array[0]=new Student("lili",34,89.2);
array[1]=new Student("huanghuang",33,90.2);
int ret=array[0].compareTo(array[1]);
System.out.println(ret);
}
}
main1结果:
main结果:
自己写bubble排序
由于后面比较一定要调用compareTo,因此参数是Comparable接口数组。数组每一个元素是对象,引用与引用之间无法比较。利用compareTo进行比较。
public class Test02 {
public static void bubbleSort(Comparable[] comparables){
for(int i=0;i<comparables.length-1;i++){
for(int j=0;j< comparables.length-1-i;j++){
if(comparables[j].compareTo(comparables[j+1])>0){
Comparable tmp=comparables[j];
comparables[j]=comparables[j+1];
comparables[j+1]=tmp;
}
}
}
}
既要根据年龄比较,又要根据分数比较。
compare(Comparator接口)
能分别实现年龄和分数同时比较。只要自己单独写比较的类就可以了。更灵活,更好。
import java.util.Arrays;
import java.util.Comparator;
class Student{
public String name;
public int age;
public double score;
public Student(String name,int age,double score) {
this.name = name;
this.age=age;
this.score=score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
class AgeComparator implements Comparator<Student>{
public int compare(Student o1,Student o2){
return o1.age-o2.age;
}
}
class ScoreComparator implements Comparator<Student>{
public int compare(Student o1,Student o2){
return (int)(o1.score- o2.score);
}
}
public class Test03 {
public static void main(String[] args) {
Student [] array=new Student[3];
array[0]=new Student("lili",34,55.2);
array[1]=new Student("huanghuang",2,90.2);
//年龄比较
AgeComparator ageComparator=new AgeComparator();
int ret=ageComparator.compare(array[0],array[1]);
System.out.println(ret);
//分数比较
ScoreComparator scoreComparator=new ScoreComparator();
System.out.println(scoreComparator.compare(array[0],array[1]));
}
}
四、clone浅拷贝与深拷贝
继承Cloneable(是一个标记接口,里面没有内容,就为了使Student与clone有关联所需它),重写clone方法,并抛出异常。还要调用clone对象是object类型(是所有类的父类),需要强转。
clone浅拷贝
import java.util.Arrays;
import java.util.Comparator;
class Student implements Cloneable{
public String name;
public int age;
public double score;
public Student(String name,int age,double score) {
this.name = name;
this.age=age;
this.score=score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student("lili",34,55.2);
Student student2=(Student) student1.clone();
System.out.println(student1);
System.out.println(student2);
}
}
clone深拷贝
要将money对象拷贝,而不是仅仅Studnent拷贝。把对象包含的所有类容拷贝完。
import java.util.Arrays;
import java.util.Comparator;
class Money implements Cloneable{
public double money;
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
class Student implements Cloneable{
public String name;
public int age;
public double score;
public Money m=new Money();//类作为成员变量
public Student(String name,int age,double score) {
this.name = name;
this.age=age;
this.score=score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
protected Object clone() throws CloneNotSupportedException{
Student tmp=(Student) super.clone();//克隆出的student对象给tmp
//Money money=(Money) tmp.m.clone();//克隆money对象。
tmp.m=(Money) this.m.clone();
return tmp;
//return super.clone();
}
}
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student("lili",34,55.2);
student1.m.money=19.9;
Student student2=(Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
student1.m.money=45.3;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
五、类中重要方法
1.object类
是所有类的父类。
可以使用object类接受所有类的对象。
2.equals方法
比较对象中的内容是否相同时一定要重写equals方法。
public boolean equals(Object obj){
Student student=(Student) obj;//逻辑自己写
return age==student.age;
}
System.out.println(student1.equals(student2));
3.hashCode方法
hashcode和equals,每个类都要重写,自定义类型在重写时习惯写上。
一般情况下,hashCode在散列表中才有用,确定对象在散列表中的位置。
利用generate-》equals和hashcode自动生成。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Double.compare(student.score, score) == 0 && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, score);
}
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student("lili",34,55.2);
Student student2=new Student("lili",34,55.2);
System.out.println(student1.equals(student2));
System.out.println(student1.hashCode());//哈希码,对象的位置
System.out.println(student2.hashCode());
}