一:抽象类
1.概念:在面向对象的概念中,所有的对象都是通过类和对象来描绘的,但是反过来,并不是所欲的类都是用来描述对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
2:语法
一个类如果被 abstract修饰称为抽象类,抽象类中被abstract修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。
注意:抽象类也是类,内部可以包含普通方法和属性,甚至构造方法。
3.抽象类特性
(1).抽象类不能直接实例化对象
abstract class Shape{
abstract public void draw();
}
public static void main(String[] args) {
Shape shape =new Shape(); //Shape 是抽象的,无法实例化。
}
(2).抽象方法不能是private的
abstract class Shape{
abstract private void draw();//非法的修饰组合,abstract和private
}
*抽象方法没有加范根限定符时,默认是public
(3):抽象方法不能被final和static修饰,因为抽象方法要被子类重写
abstract class Shape{
abstract final void funcA();
abstract public static funcB();
}
(4):抽象类必须被继承,并且继承后子类要重写父类中的抽象方法
class Rect extends Shape {
private double length;
private double width;
public Rect(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public void draw() { //重写父类的draw()方法
System.out.println("矩形:length=" + length + "width=" + width);
}
}
如果不重写父类中的抽象方法,则子类必须为抽象类,否则报错。
class Triangle extends Shape { //此时报错
private double a;
private double b;
private double c;
}
abstract class Triangle extends Shape { //加上abstract不报错
private double a;
private double b;
private double c;
}
(5)抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
(6)抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
4.抽象类的作用
抽象类的作用就是被继承。
普通的类也可以被继承,普通的方法也可以被重写,为什么要引入一个抽象类的概念呢?------
实际工作中有些代码不应该由父类完成,而应该由子类完成,如果此时不小心误用成父类了,使用普通类编译器是不会报错的,但是父类抽象类就会在实例化的时候提示错误,以便于早些发现问题
二:接口
1.概念
在JAVA中,接口可以看成是,多个累的公共规范,是一种引用数据类型
2.语法规则
接口的定义格式与定义类的格式基本相同,将class关键字换成interface关键字,就定义了一个接口
interface IA{
public abstract void methodA();//public abstract 是固定搭配,可以不写
public void methoddB();
abstract void methodC();
void methodD(); //推荐使用该书写方法
}
提示:
(1)创建接口时,接口的命名一般已大写字母 I 开头
(2)接口的命名一般使用“形容词”磁性的单词
(3)接口的方法和属性不要任何修饰符号,保持代码的简洁性
3.接口使用
接口不能直接使用,必须要有一个“实现类”来实现该接口,实现接口中的所有抽象方法。
class B implements IA{
//..重写接口中的方法
}
注意:子类和父类之间是extends 继承关系,类与接口之间是 implements关系。
例:请实现笔记本电脑使用USB鼠标,USB键盘的例子
1.USB接口:包含打开设备,关闭设备功能。
2.笔记本类:包含开机功能,关机功能,使用USB设备功能
3.鼠标类:实现USB接口,并具备点击功能
4.键盘类:实现USB接口,并具备输入功能
interface USB {
void openDevice();
void closeDevice();
}
//鼠标类,实现USB接口
class Mouse implements USB {
@Override
public void openDevice() {
System.out.println("打开鼠标");
}
@Override
public void closeDevice() {
System.out.println("关闭鼠标");
}
public void click() {
System.out.println("鼠标点击");
}
}
//键盘类,实现USB接口
class KeyBoard implements USB {
@Override
public void openDevice() {
System.out.println("打开键盘");
}
@Override
public void closeDevice() {
System.out.println("关闭键盘");
}
public void input() {
System.out.println("键盘输入");
}
}
//笔记本类,使用USB设备
class Computer {
public void powerOn() {
System.out.println("打开笔记本电脑");
}
public void powerOff() {
System.out.println("关闭笔记本电脑");
}
public void useDevice(USB usb) {
usb.openDevice();
if (usb instanceof Mouse) { //向下转型的判断
Mouse mouse = (Mouse) usb;//必须把usb强转为Mouse类型,因为usb中没有具体的鼠标点击等方法
mouse.click();
} else if (usb instanceof KeyBoard) {
KeyBoard keyBoard = (KeyBoard) usb;
keyBoard.input();
}
usb.closeDevice();
}
}
public class Test3 {
public static void main(String[] args) {
Computer computer = new Computer();
computer.powerOn();
//使用鼠标设备
computer.useDevice(new Mouse());
//使用键盘设备
computer.useDevice(new KeyBoard());
computer.powerOff();
}
}
打开笔记本电脑
打开鼠标
鼠标点击
关闭鼠标
打开键盘
键盘输入
关闭键盘
关闭笔记本电脑
4.接口特性
(1)接口类型是一种引用类型,不能直接new接口的对象
(2)接口中每一个方法都是public的抽象方法,接口中的方法会被隐式指定为public abstract,其他的修饰符会出错。
interface ITest{
private void testDemo() ;//接口中不允许引用private
void testDemo1();
}
(3)接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
interface ITest{
void testDemo() ;
void testDemo1(){ //接口abstract方法不能有主体
System.out.println("试图在接口中实现");
}
}
(4)重写接口中方法时,不能使用默认的访问权限修饰
例如:
interface ITest{
void testDemo() ;
}
class A implements ITest{
@Override
public void testDemo() { //此处的public若是省略掉则会报错
}
}
(5)接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量
interface ITest {
double a = 3.0; //默认被 public static final修饰
}
public class Test4 {
public static void main(String[] args) {
System.out.println(ITest.a); //此处可以通过接口名直接访问,说明是静态的
}
ITest.a=2.0; //此处报错,说明变量具有final属性
}
(6)接口中不能有静态代码快和构造方法
interface ITest {
public ITest{
} //编译失败
{} // 编译失败
}
(7)接口虽然不是类,但是接口编译完成后字节码文件的后缀也是.class
(8)如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
class Frog extends Aniaml implements IRunning,ISwimming{
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(name+"正在跳着跑");
}
@Override
public void swim() {
System.out.println(name+"正在蛙泳");
}
} // 此处若只实现一个接口,则会报错。如果必须只实现一个接口,那么必须设置成abstract类
三:实现多个接口
JAVA中不支持多继承,但是一个类可以实现多个接口。
class Aniaml {
protected String name;
public Aniaml(String name) {
this.name = name;
}
void eat() {
System.out.println("正在吃饭");
}
}
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
//猫可以跑
class Cat extends Aniaml implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(name + "正在用四条腿跑");
}
@Override
void eat() {
System.out.println(name + "正在吃猫粮");
}
}
//鱼可以游泳
class Fish extends Aniaml implements ISwimming {
public Fish(String name) {
super(name);
}
@Override
public void swim() {
System.out.println(name + "正在用尾巴游泳");
}
void eat() {
System.out.println(name + "正在吃鱼粮");
}
}
//青蛙 能跑,能游泳
class Frog extends Aniaml implements IRunning, ISwimming {
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(name + "正在跳着跑");
}
@Override
public void swim() {
System.out.println(name + "正在蛙泳");
}
void eat() {
System.out.println(name + "正在吃蛙粮");
}
}
//鸭子可以跑,游泳,飞
class Duck extends Aniaml implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(name + "正在用翅膀飞");
}
@Override
public void run() {
System.out.println(name + "正在用两条腿跑");
}
@Override
public void swim() {
System.out.println(name + "正在飘在水上");
}
void eat() {
System.out.println(name + "正在吃鸭粮");
}
}
class Robot implements IRunning {
@Override
public void run() {
System.out.println("机器人正在跑");
}
}
public class Test5 {
public static void walk(IRunning iRunning) {
iRunning.run();
}
public static void swim(ISwimming iSwimming) {
iSwimming.swim(); //这两个方法不关注是哪个类型的
}
public static void eat(Aniaml aniaml) {
aniaml.eat(); //这个方法必须是Animal类型的
}
public static void main(String[] args) {
walk(new Duck("小黄鸭"));
walk(new Frog("小青蛙"));
eat(new Duck("大鸭子"));
walk(new Robot());
swim(new Frog("青蛙二号"));
swim(new Fish("鲤鱼"));
}
}
小黄鸭正在用两条腿跑
小青蛙正在跳着跑
大鸭子正在吃鸭粮
机器人正在跑
青蛙二号正在蛙泳
鲤鱼正在用尾巴游泳
这样做的好处是可以使人忘记类型,有了接口之后,类的使用者就可以不必关注具体类型,而只关注某个类是否具备某种能力。
四:接口间的继承
接口与接口之间可以多继承,达到复用的效果,使用extends 关键字
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
interface Icanswimandrun extends IRunning,ISwimming{
//...
}
接口间的继承相当于把多个接口合并 在一起
五:接口使用实例
1.给对象数组排序
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
}
public class Test6 {
public static void main(String[] args) {
Student[] students = new Student[]{
new Student("张三", 20),
new Student("张四", 15),
new Student("张五", 18),
new Student("张六", 22),
};
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
当我们需要给上述学生对象排序时,使用sort方法,会报错,因为不知道是根据年龄排还是姓名排。
所以此时需要用Student类实现Comparable接口,并实现其中的compareTo方法
class Student implements Comparable {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String toString() {
return "[" + this.name + ":" + this.score + "]";
}
@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;
}
}
}
六:抽象类和接口的区别
抽象类中可以包含普通方法和普通字段,这样的普通方法和普通字段可以被子类直接使用(不必重写),而接口中不能包含普通方法,子类必须重写所有的抽象方法。
七:Object类
1.对象比较equals方法
在java中,==进行比较时:
a.如果==左右两侧是基本类型变量,比较的是变量中的值是否相同
b.如果==左右两侧是引用类型变量,比较的是引用变量地址是否相同
c.如果要比较对象中的内容,必须重写Object中的equals方法,因为equals方法默认也是按照地址比较的
class Person2 {
private String name;
private int age;
public Person2(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test8 {
public static void main(String[] args) {
Person2 p1 = new Person2("jialin", 21);
Person2 p2 = new Person2("jialin", 21);
int a = 10;
int b = 10;
System.out.println(a == b);
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
}
}
输出:
true
false
false
Person类重写equals方法后,然后比较:
class Person2 {
private String name;
private int age;
public Person2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj)
//----------------------------------------------------------------------------
if (obj == null) {
return false;
}
if (this == obj) {
return true; //此区域为对obj做出判断
}
//不是Person2类对象
if (!(obj instanceof Person2)) {
return false;
}
//-----------------------------------------------------------------------------
Person2 person = (Person2) obj; //此区域为重写的内容
if (this.name.equals(person.name) && this.age == person.age) {
return true;
}
return false;
}
}
public class Test8 {
public static void main(String[] args) {
Person2 p1 = new Person2("张三", 21);
Person2 p2 = new Person2("张三", 21);
int a = 10;
int b = 10;
System.out.println(a == b);
System.out.println(p1 == p2);
System.out.println(p1.equals(p2)); //重写后为 true
}
}
结论:比较对象中内容是否相同时,一定要重写equals方法
2.hashcodde方法 (计算一个对象的位置)
class People {
public String name;
public int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test9 {
public static void main(String[] args) {
People people1 = new People("小红", 20);
People people2 = new People("小红", 20);
System.out.println(people1.hashCode());
System.out.println(people2.hashCode());
}
}
执行结果:
460141958
1163157884
注意:两个完全一样的对象的hash值不一样。
当我们重写hashCode()方法时
class People {
public String name;
public int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return Objects.hash(name,age);
}
}
public class Test9 {
public static void main(String[] args) {
People people1 = new People("小红", 20);
People people2 = new People("小红", 20);
System.out.println(people1.hashCode());
System.out.println(people2.hashCode());
}
}
//执行结果
23653826
23653826 注意事项:哈希值一样。
结论:
1,hashcode方法用来确定对象中内存存储的位置是否相同
2.事实上hashCode()在散列表中才有用,在其他情况下没用。在散列表中hashCode()的作用时获取对象的散列码,进而确定该对象在散列表中的位置。
equals()方法和 hashCode()方法一般来说都使用编译器默认生成的,不需要我们自己书写。
本文详细介绍了Java中的抽象类和接口,包括它们的概念、语法、特性及应用场景。抽象类主要用于被继承,不能直接实例化,其抽象方法需在子类中重写。接口则定义了多个类的公共规范,类通过implements接口并实现其所有抽象方法。文章还讨论了实现多个接口、接口间的继承以及抽象类与接口的区别,并给出了实际使用示例。
5639

被折叠的 条评论
为什么被折叠?



