一,抽象类
抽象类为用abstract修饰的类
1,定义的成员变量与普通的类没有区别
2,抽象类不可以被实例化
3,当一个类不具体描述某个对象时,可以定义为抽象类
4,如果一个类包含抽象方法,则这个类必须是抽象类,没有抽象方法,也可以被称为抽象类
5,一个方法可以被修饰为abstract,这个方法可以不被实现,被称为抽象方法
例如:public abstract void draw();
6,抽象类也可以发生向上转型,动态绑定,多态
7,抽象方法,满足重写特点,(一定要被子类重写)被static,final,private、修饰都是不能发生重写的
@Override
public void draw() {
System.out.println("画一个矩形");
}
}//对draw()方法的重写
8,当一个普通类A,继承了一个抽象方法,但不想重写抽象类的方法,可以把A改为一个抽象类,但如果A被B继承,则B这个类要重写所有的抽象方法
二,接口
1,接口用interface来定义
2,接口中的成员变量默认被public static final修饰,且接口中的成员变量必须要初始化。所以有以下两种写法:
法一:public static final int age1=10; 法二:int age1=10;
3,接口的方法,默认被public abstract修饰,故为抽象方法,不能有具体的实现,一般直接写为void draw();
4,接口为引用类型,所以不能被实例化为对象
5,接口中定义的方法能具体的实现的有两种:第一种为default修饰的方法,第二种为静态方法
void text1(); public static void text2 (){ System.out.println("静态方法"); } public default void text3(){ System.out.println("default方法"); }//接口中的方法 @Override public void text1() { System.out.println("重写text1"); } @Override public void text3() { System.out.println("重写default");//在实现接口的类中,对接口方法进行重写
我们可以通过实例化,用对象的引用来访问重写的text1和text3,也可以用接口名访问访问接口中的静态方法<A.text2();>。default修饰的方法并不是必须要重写的。
6,使用接口时,用关键字implements来实现。例如:class A implements IB{}
7,当一个类实现了这个接口,就要对接口中的方法进行重写(因为接口中的方法为抽象方法)
8,一个类可以实现多个接口,但这个类一定要重写以上接口中的全部抽象方法。例如:
interface IA{
void textA();
}
interface IB{
void textB();
}
class Demo2 implements IA ,IB{
@Override
public void textA() {
System.out.println("textA");
}
@Override
public void textB() {
System.out.println("textB");
}
}
9,接口可以继承多个接口,用关键字extends来实现。例如:interface IA{};interfaceI B{};interface IC extends IA,IB{};而实现接口IC的这个类中,一定要重写IA,IB,IC中的所有抽象方法。
接口的初步练习:
public interface IUSB {
void openDevice();
void closeDevice();
}--------------------------
public class KeyBoard implements IUSB{
@Override
public void openDevice() {
System.out.println("打开键盘");
}
@Override
public void closeDevice() {
System.out.println("关闭键盘");
}
public void input(){
System.out.println("键盘输入");
}
}----------------------------------------
public class Mouse implements IUSB{
@Override
public void openDevice() {
System.out.println("打开鼠标");
}
@Override
public void closeDevice() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("点击鼠标");
}
}--------------------------------------------
public class Computer {
public void powerOff(){
System.out.println("关闭电脑");
}
public void powerOn(){
System.out.println("打开电脑");
}
public void useDevice(IUSB usb){
usb.openDevice();
if (usb instanceof Mouse){
Mouse mouse=(Mouse)usb;
mouse.click();
}
if(usb instanceof KeyBoard){
KeyBoard keyBoard=(KeyBoard) usb;
keyBoard.input();
}
usb.closeDevice();
}
public static void main(String[] args) {
Computer computer=new Computer();
computer.powerOn();
computer.useDevice(new KeyBoard());
computer.useDevice(new Mouse());
computer.powerOff();
}
}
10,一个类可以同时继承抽象类和实现多个接口:
public abstract class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat();
}//抽象类
public interface IFly {
void fly();
}//第一个接口
public interface IRunning {
void run();
}//第二个接口
public interface ISwamming {
void swam();
}//第三个接口
public class Duck extends Animal implements ISwamming,IFly,IRunning{
public Duck(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println(this.name+"吃鸭粮");
}
@Override
public void fly() {
System.out.println(this.name+"飞...");
}
@Override
public void run() {
System.out.println(this.name+"跑...");
}
@Override
public void swam() {
System.out.println(this.name+"游泳...");
}
}
public static void eatfunc(Animal animal){
animal.eat();
}
public static void runfunc(IRunning running){
running.run();
}
eatfunc(new Fish("小鱼",3));
11, 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
12,接口的实例:
想要比较对象中的成员变量的数值大小,因为它为引用数据类型,所以不能直接比较,此时需要一个接口,来实现比较,这个接口为Comparable<T>。
class Student implements Comparable<Student>{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
if(this.name.compareTo(o.name)>0){
return 1;
} else if (this.name.compareTo(o.name)==0) {
return 0;
}else {
return -1;
}//对方法的重写(姓名的比较)
}
@Override
public int compareTo(Student o) {
if(this.age>o.age){
return 1;
}else if(this.age==o.age){
return 0;
}else{
return -1;
}
}//对方法的重写(年龄的比较)
}
public static void main1(String[] args) {
Student student1=new Student("zhangsan",12);
Student student2=new Student("lisi",10);
if(student1.compareTo(student2)>0){
System.out.println("student1>student2");
}else{
System.out.println("student1<=student2");
}
}
-------------------------------------------------
public static void mysort(Comparable[] comparable){
for(int i=0;i<comparable.length-1;i++){
for (int j=0;j<comparable.length-1-i;j++){
if(comparable[j].compareTo(comparable[j+1])>0){
Comparable tmp=comparable [j];
comparable[j]=comparable[j+1];
comparable[j+1]=tmp;
}
}
}
}
public static void main(String[] args) {
Student[]students=new Student[3];
students[0]=new Student("zhangsan",12);
students[1]=new Student("lisi",8);
students[2]=new Student("wamgwu",10);
System.out.println(Arrays.toString(students));
//Arrays.sort(students);
mysort(students);
System.out.println(Arrays.toString(students));
}在 Arrays.sort();方法中会自动调用 compareTo 方法(所以在用sort比较时,也需要实现Comparable<T>接口). compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象. 然后比较当前对象和参数对象的大小关系.
(1)在接口Comparable<T>中有一个方法compareTo,需要对这个方法进行重写。
(2)Comparable接口有局限性,一旦写死了比较方式,后期就不能随意更改了
(3) 自己实现比较代码时,mysort(students);中的students,使用接口来接收的,所以自己实现比较代码时,也需要实现接口Comparable<T>,下图为Student类没有实现接口所报出的错误
也可以使用 Comparator<T>来实现比较。
public class Agecomparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age- o2.age;
}
}//年龄比较器
public class Namecomparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}//名字比较器
public static void main1(String[] args) {
Student student1=new Student("zhangsan",9);
Student student2=new Student("lisi",10);
Agecomparator agecomparator=new Agecomparator();
int ret=agecomparator.compare(student1,student2);
System.out.println(ret);
Namecomparator namecomparator=new Namecomparator();
int ret2=namecomparator.compare(student1,student2);
System.out.println(ret2);
}
-------------------------------------------------------
public static void main(String[] args) {
Student[]students=new Student[3];
students[0]=new Student("zhangsan",12);
students[1]=new Student("lisi",8);
students[2]=new Student("wamgwu",10);
Namecomparator namecomparator=new Namecomparator();
System.out.println(Arrays.toString(students));
Arrays.sort(students,namecomparator);
System.out.println(Arrays.toString(students));
}//调用namecomparator来比较students。
13,深拷贝
class Student implements Cloneable{ 必须实现cloneable接口(空接口、标记接口),只要实现这个克隆接口,证明这个类才能被实现clone int age; public Student(int age) { this.age = age; } @Override public String toString() { return "Student{" + "age=" + age + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } 所有的类都继承object,因为object父类下面的方法为protected clone,父类,子类的包不同,不能直接访问,需要用到super } public class Text { public static void main(String[] args) throws CloneNotSupportedException{ Student student1=new Student(10);异常问题 Student student2=(Student) student1.clone(); 为向下转型,所以要强制类型转换 } } -------------------------------------------------------------------------
class Money implements Cloneable{
double money=12.5;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student implements Cloneable{
int age;
Money m=new Money();
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student tmp=(Student) super.clone();
tmp.m=(Money) this.m.clone();
return tmp;
}
}
public class Text {
public static void main(String[] args) throws CloneNotSupportedException{
Student student1=new Student(10);
Student student2=(Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
System.out.println("--------------");
student2.m.money=100;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
浅拷贝:
浅拷贝克隆出的student2跟student1里面的数据一模一样,所以两者中的m都指向同一块空间(m为引用类型,存储的为地址)
深拷贝:

三,抽象类与接口的区别
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中 不能包含普通方法, 子类必须重写所有的抽象方法
四,Object类
Object是Java默认提供的一个类。Java里面除了Object类,所有的类都是存在继承关系的。默认会继承Object父 类。即所有类的对象都可以使用Object的引用进行接收。
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
Person person=(Person) obj;
if(this.name.equals(person.name)){
return true;
}else return false;
}//重写实现想要实现的功能
public static void main(String[] args) {
Person person1=new Person("zhangsan",10);
Person person2=new Person("zhangsan",9);
System.out.println(person1.equals(person2));
}
因为person1和person2为引用类型,比较的地址,并不能实现想实现的功能,所以需要重写equals
hashcode方法(算出具体对象的位置):
Person person1=new Person("zhangsan",10);
Person person2=new Person("zhangsan",10);
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
此时输出的为两个不同的地址;
从代码上看,是两个不同的对象,但从逻辑上来说,名字,年龄一样,就是同一个人,所以想要这两个对象放到同一个位置,也就是想要两个哈希值是同样的,所以需要重写hashcode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
以后只要是自定义类型,一定要重写hashcode方法和equals方法。










