目录
一.抽象类
1.什么是抽象类
(1)抽象类的概念
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
简单的说就是如果一个类不能体的描绘一个对象时,我们可以把这个类设置为抽象类。
(2)抽象类例子
1.对于一个动物,每种动物吃的东西不同,我们可以将该类设置为抽象类,对于吃这种行为,我们将它设置为抽象方法
2.对于一个图形类,我们想要画一个图形,没有具体的不知道要画什么,所以我们可以将它设置为一个抽象类,对于画这种行为,我们也将它设置为抽象方法。
2.如何定义抽象类
(1)定义抽象类
通过使用abstract关键字来进行定义,如果一个类被abstract修饰,该类就为抽象类;如果一个抽象类中的方法被abstract修饰,该方法就为抽象方法。
(2)代码举例
3.抽象类的注意事项
(1)抽象类也为类,可以包含普通的成员变量和成员方法,构造方法。
(2)抽象类不能实例化对象
(3)抽象方法不能被final private,static修饰,因为抽象方法需要在子类中进行重写。
(4)抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract修饰
代码:(这里可以使用快捷键生成需要重写的方法:ctrl+o)
public class TestShape{
public static void main(String[] args) {
}
}
//等边三角形
class EqualSidesTriangle extends Triangle{
public EqualSidesTriangle(int a, int b, int c) {
super(a, b, c);
}
@Override
void circumference() {
System.out.println("等边三角形周长:"+(a+b+c));
}
}
//三角形
abstract class Triangle extends Shape{
int a;
int b;
int c;
public Triangle(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
@Override
void draw() {
System.out.println("画三角形");
}
}
//图形
abstract class Shape{
abstract void draw();//画
abstract void circumference();//周长
}
(5)抽象类中不一定有抽象方法,但是有抽象方法的一定是抽象类
在抽象类中可以没有抽象方法,但是有abstract修饰的方法,该类一定为abstract类。
(6)在重写方法的时候要注意在子类中重写的方法的权限修饰符不能小于抽象类中对应的抽象方法权限修饰符。
4.为什么要有抽象类
了解了抽象类后,我们会有这样一个疑问,就是抽象类和父类的继承中方法的重写和调用都是一样的,为什么还要有这种抽象类呢,由于抽象类不能创建对象,实际需求是要子类进行,但是不小心创建了父类的对象后,编译器会自动地通过校验,并提示你该抽象类不能被实例化,相当于多了一层校验的工作。有时候我们是需要这样做的。
二.接口
1.什么是接口
在我们生活中,typc类型的充电接口,电脑的usb接口,还有电源插座,这些都为接口,接口相当于一个规范,别的东西只有通过这个规范才可以进行使用。
接口的概念:接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.如何定义接口
接口定义和类相似,只需要将class关键字改为interface就行。
(1)写法
一般我们将接口名都首字母大写为I。2.
public interface IInterface{
}
(2)在idea中如何使用
和定义类是相似的
3.接口的使用
定义了接口之后,我们如何在类中进行使用呢,这里我们使用implements关键字来进行实现。
(1)使用例子
1.动物接口
public interface IAnimal {
void eat();
void sleep();
}
2.测试类,猫类,狗类
public class TestAnimal {
public static void main(String[] args) {
IAnimal animal = new Dog("二狗");
IAnimal animal2 = new Cat("小白猫");
animal.eat();
animal.sleep();
animal2.eat();
animal2.sleep();
}
}
//狗类
class Dog implements IAnimal{
String name;
public Dog(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println(name+"吃骨头");
}
@Override
public void sleep() {
System.out.println(name+"睡觉");
}
}
//猫类
class Cat implements IAnimal{
String name;
public Cat(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println(name+"吃猫粮");
}
@Override
public void sleep() {
System.out.println(name+"睡觉");
}
}
3.运行结果
4.接口的特点
(1)接口是一种引用类型,不能实例化对象
(2)接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错)
(3)接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
(4)接口中的方法是不能在接口中实现的,只能由实现接口的类来实现(这里和抽象类不同,抽象类中可以有实现的方法)
(5)接口编译形成的字节码文件后缀也为class
(6)由于接口中的方法默认带有public,所以在重写方法时,重写的方法只能用public来修饰,其他修饰符的权限都比较低不能使用
重写时的权限大小为:public>default>protected.
(7)接口中不能有静态代码块和构造方法
接口中的变量中只能为public static final 类型,所以接口中不能有构造方法。
5.一个类实现多个接口
在Java中类继承中,不能使用一个子类不能同时继承多个基类,但是Java中一个类可以实现多个接口,通过接口我们可以实现和多继承同样的功能。
(1)例一
public class TestAnimal {
public static void main(String[] args) {
// IAnimal animall = new IAnimal();//不能实例化
Dog dog = new Dog("二狗子");
Bird bird =new Bird("大雁");
dog.run();
bird.fly();
}
}
//狗类
class Dog implements IAnimal,IRunning{
String name;
public Dog(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println(name+"吃骨头");
}
@Override
public void sleep() {
System.out.println(name+"睡觉");
}
@Override
public void run() {
System.out.println(name+"跑");
}
}
//鸟类
class Bird implements IAnimal,IFly{
String name;
public Bird(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println(name+"吃虫子");
}
@Override
public void sleep() {
System.out.println(name+"巢穴睡觉");
}
@Override
public void fly() {
System.out.println(name+"天上飞");
}
}
注意:
1.如果该类对于实现接口后的抽象方法没有都实现,那么该类就需设置为抽象类。
2.继承中的关系为is-a,而接口是具有什么特性,所以一个对象可以有多个特性,而只能是一个。
3.使用接口也体现了Java中的多态特性。
(2)例二
接口实现多态举例:
代码:
public class TestRun {
//调用跑的方法
public static void animalRun(IRunning runing){
runing.run();
}
public static void main(String[] args) {
Chick chick = new Chick("小鸡");
Frog frog = new Frog("小青蛙");
animalRun(chick);
animalRun(frog);
}
}
//鸡类
class Chick implements IRunning{
String name;
public Chick(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"跑");
}
}
//青蛙类
class Frog implements IRunning{
String name;
public Frog(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name+"跳");
}
}
//跑的接口
interface IRuning{
void run();
}
运行结果:
6.接口之间的继承
之前在学习继承时,知道了子类只能继承一个基类,但是在接口中就可以实现多继承,一个接口可以继承多个接口,因此可以使用接口达到多继承的目的。
代码实例:
public class Swan implements IAmphibious {
String name;
public Swan(String name) {
this.name = name;
}
public static void main(String[] args) {
IAmphibious swan = new Swan("天鹅");//这里使用接口的引用,向上转型
swan.run();
swan.swim();
swan.sleep();
}
@Override
public void run() {
System.out.println(name+"地上跑");
}
@Override
public void swim() {
System.out.println(name+"水里游");
}
@Override
public void sleep() {
System.out.println(name+"睡觉");
}
}
//跑
interface IRun{
void run();
}
//游
interface ISwim{
void swim();
}
//两栖动物既可以跑又可以在水里游,可以继承多个接口
interface IAmphibious extends IRun,ISwim{
void sleep();
}
运行结果:
接口的继承相当于是将所有的接口合并在一起。
7.接口实例之对象的排序
注:这里的举例和说明都是以Student类进行举例说明。
(1)排序前的引言
之前学习类和对象的时候,里面有一个toString方法,可以将对象信息通过打印进行显示,那么现在我们想将对象根据某种规则进行排序,我们知道Java中在Arrays类下有一个sort()可以进行对基本数据类型进行排序,那么可以将对象进行排序吗,我们验证一下。
(2)使用Comparable接口进行排序
实现了Comparable接口后需要重写该接口里面的compareTo(Object o)这个方法,重写的规则如下:
1.Object o这个参数传入的是Student类型的对象
2.我们按照自己指定的规则来进行排序(这里以学生的score来进行排序)
在学习类和对象的时候,知道在成员方法中,系统会默认有一个Student this参数,这个参数指的是当前对象,而Object o 是参数对象。
3.我们通过当前对象和参数对象中的score进行比较大小,如果想要按照升序排序,就指明当前对象的score值大于参数对象中的score时返回一个大于0的数(一般返回1);当前对象的score小于参数对象的score时返回一个小于0的数(一般返回-1);相等返回0。
4.如果需要升序,则只需要把上面的返回1和-1调换即可。
代码举例:
import java.util.Arrays;
public class Student implements Comparable{
String name;
String gender;
int score;
public Student(String name, String gender, int score) {
this.name = name;
this.gender = gender;
this.score = score;
}
public static void main(String[] args) {
Student[] stu = {new Student("张三","男",95),
new Student("小李","男",87),
new Student("小红","女",60),
new Student("小吴","男",100),
};
//将对象进行排序
Arrays.sort(stu);
//打印排序好的对象
for (int i = 0; i < stu.length; i++) {
System.out.println(stu[i]);
}
}
//进行对象之间的比较
@Override
public int compareTo(Object o) {
Student student = (Student) o;
//升序排序
if(this.score> student.score){
return 1;
}else if(this.score<student.score){
return -1;
}else{
return 0;
}
}
//重写toString()是为了打印的时候可以看到对象的具体信息
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", score=" + score +
'}';
}
}
运行结果:
为什么直接只调用排序方法不调用compareTo()方法就能排序?
这是因为Java在调用sort()方法时会自动调用该比较方法。
总结:
在使用了排序方法之后,Java是需要判断传入的对象是否具有compareTo()这样的能力,我们通过重写该方法,实现了这样的能力。通过我们指定的规则来进行比较,这里不止可以score排序,也可以根据姓名进行排序,这里的排序规则需要我们自己指定。