JavaSE学习之--抽象类,接口,内部类(一)+https://developer.aliyun.com/article/1413496
8.在jdk8中:接口还可以包含default方法
我们知道接口中的方法都是抽象方法,不含有主体,但在jdk8中引入了一个新特性-->default关键字,在接口中,如果方法被default修饰,则此方法可以含有主体,且在类中不必须被重写(相当于自动继承了)
interface IUSB { void method1(); default void method2() { System.out.println("This is a default method!"); } } class Mouse implements IUSB { @Override public void method1() { System.out.println("hehe"); } // method2不重写也不会报错 // 相当于“自动继承” } public class Test1 { public static void main(String[] args) { Mouse mouse = new Mouse(); mouse.method1(); // 没有重写method2,也能调用该方法,证明该方法被“自动继承”了 mouse.method2(); } }
4.实现多接口
Java中类是单继承的,一个类无法继承多个类(不能有多个父亲),但可以同时实现多个接口!
通过implements+','实现多个接口!!!
下面通过类来表示一组动物
class Animal { protected String name; public Animal(String name) { this.name = name; } }
另外提供一些接口,分别表示 "会飞的", "会跑的", "会游泳的".
interface IFlying { void fly(); } interface ISwimming { void swim(); } interface IRunning { void run(); }
猫类:跑
// 猫类 class Cat extends Animal implements IRunning { public Cat(String name) { super(name); } // ctrl+i快速调出接口抽象方法的重写 @Override public void run() { System.out.println(this.name + "猫正在跑步"); } }
狗类:跑,游
// 狗类 跑+游 class Dog extends Animal implements IRunning,ISwimming { public Dog(String name) { super(name); } @Override public void swim() { System.out.println(this.name + "正在狗刨"); } @Override public void run() { System.out.println(this.name + "狗正在跑步"); } }
鸭子类:跑,游,飞
// 鸭子类 跑,飞,游 class Duck extends Animal implements IRunning,ISwimming,IFlying { public Duck(String name) { super(name); } @Override public void fly() { System.out.println(this.name + "鸭子正在飞"); } @Override public void swim() { System.out.println(this.name + "鸭子正在游泳"); } @Override public void run() { System.out.println(this.name + "鸭子正在跑步"); } }
注意:一个类实现多个接口时,所有接口中的抽象方法都要被重写!!!
public class Test1 { public static void main(String[] args) { Dog dog = new Dog("mimi"); dog.run(); dog.swim(); System.out.println("================"); Cat cat = new Cat("jiji"); cat.run(); System.out.println("================"); Duck duck = new Duck("hehe"); duck.fly(); duck.run(); duck.swim(); } }
上面代码展示了Java面向对象编程中最常见的用法:一个类继承一个父类,同时实现多个接口!!
可以理解为接口时“部分共性”,但本质还是为了代码复用
继承表达式是is-a语义,接口表达的含义是“具有xxx特性”
- 猫是一种动物, 具有会跑的特性.
- 狗也是一种动物, 既能跑, 也能游泳
- 鸭子也是一种动物, 既能跑, 也能游, 还能飞
这样做的好处是可以让程序员忘记类型,只关注实现特性,关注某个类是否具有该特性
比如我们可以创建一个Robot类,他也可以实现IRunning接口,尽管他不是Animal类!
class Robot implements IRunning { @Override public void run() { System.out.println("the robot is running!"); } }
创建一个方法调用接口中的方法(接口作为参数)
public class Test1 { // 接口和类一样,可以作为参数类型,当对象传递时发生动态绑定 // 谁实现了接口,谁就可以调用接口方法 public static void Run(IRunning running) { running.run(); } public static void main(String[] args) { // 匿名对象的直接调用 Run(new Cat("jiji")); Run(new Dog("mimi")); Run(new Duck("hehe")); Run(new Robot()); }
5.接口之间的继承
接口之间也存在继承关系,不同于类的是,一个接口可以继承多个接口
interface IRunning { void run(); } interface ISwimming { void swim(); } // 两栖的动物, 既能跑, 也能游 interface IAmphibious extends IRunning, ISwimming { } class Frog implements IAmphibious { ... }
通过接口继承创建一个新的接口 IAmphibious 表示 "两栖的". 此时实现接口创建的 Frog 类, 就继续要实现 run 方 法, 也需要实现 swim 方法,同时继承两个接口!!!
6.抽象类和接口的区别:
1.成员变量:抽象类中可以含有普通成员变量,接口中的成员变量都是被public static final修饰的
2.方法:抽象类中既可以有抽象方法也可以有普通方法,而接口中所有的方法都是public abstract修饰
3.继承关系:一个类只能继承一个父类,但可以实现多个接口。但接口与接口之间只有继承关系
三. Object类
Object类是Java中默认提供的一个类,他是所有类的父类,是类的“祖先”。为什么会有这么一个类呢?其实也很好理解,Java是一个面向对象编程的语言,它存在很多自定义的类,那程序员是如何写出这些自定义的类呢?本质上还是通过Object这个祖先类来开发的!!!
1.Object可以接受任意类型的对象
class Person{}; class Stu{}; public class Test1 { // 此处发生了向上转型 public static void func(Object object) { System.out.println(object); } public static void main(String[] args) { func(new Person()); func(new Stu()); } }
2.Object本质上还是Java中的一个类,含有一些自带的方法
本文主要讲解equals,hashcode,toString方法
1.toString方法--获取对象信息
前面我们已经重写了很多toString方法,当时可能很不理解为什么toString方法要重写呢?他是来源于哪个类呢?现在可以解释这个问题了,toString方法是Object类自带的一个方法,所有的类都是Object的子类,所以要重写toString方法来实现我想获取的信息
toString的源码
2.equals方法--进行对象比较
在Java中,==比较时
如果左右两侧是基本数据类型(int等等),直接比较值的大小即可
如果左右两侧是引用数据类型(比如对象),实际上比较的是引用类型的地址是否相同
如果想比较对象中的内容,就要重写equals方法
equals的源码:
public static void main(String[] args) { Person person1 = new Person(); Person person2 = new Person(); // 当两个引用类型比较时,实际上比较的是地址 System.out.println(10 == 20);// false System.out.println(person1 == person2);// false System.out.println(person1.equals(person2));// false System.out.println("======================="); person2 = person1; System.out.println(person1.equals(person2));// true }
两个对象的比较是判断对象的地址是否相同,也即是在内存中存储的位置是否相同
Person person1 = new Person("lisi",18); Person person2 = new Person("lisi",18); System.out.println(person1.toString()); System.out.println(person2.toString());
可以看出,两个对象的地址不同
重写equals方法 :
假如我想使用Person类中的age来判断两个对象是否相同,此时就要重写equals方法
class Person{ int age; public Person(int age) { this.age = age; } @Override public boolean equals(Object object) { // 两个对象地址相同,直接返回true if (this == object) return true; // 比较的对象是null或两个对象的类型不同,直接返回false if (object == null || getClass() != object.getClass()) return false; // 此处进行向下转型 Person person = (Person) object; return age == person.age; } @Override public int hashCode() { return Objects.hash(age); } } public class Test1 { public static void main(String[] args) { Person person1 = new Person(10); Person person2 = new Person(20); Person person3 = new Person(20); System.out.println(person1.equals(person2));// false System.out.println(person2.equals(person3));// true }
注意:可以通过快捷键快速生成toString和hashcode的重写方法
结论:通过对象中的内容进行比较时,一定要重写toString方法!
JavaSE学习之--抽象类,接口,内部类(三)+https://developer.aliyun.com/article/1413501