추상 클래스란 무엇인가요? 이름에서 알 수 있듯이 추상 클래스는 매우 추상적입니다. 즉, 이 클래스를 설명할 정보가 충분하지 않으면 해당 클래스를 설명할 필요가 없습니다.
예를 들어 코드 사용:
class Shape { public void draw() { System.out.println("我要画图形!!"); } } class circle extends Shape { @Override public void draw() { System.out.println("我要画圆形!!!"); } } class rect extends Shape { @Override public void draw() { System.out.println("我要画矩形!!!"); } } public class TestDemo3 { public static void drawShape(Shape shape) { shape.draw(); } public static void main(String[] args) { drawShape(new circle()); drawShape(new rect()); } }
이 작은 사례를 사용하여 다형성을 검토합니다. Shape 상위 클래스를 만든 다음 두 개의 하위 클래스, 즉 ect 클래스와 Circle 클래스를 만든 다음 이 두 클래스를 사용합니다. 동일한 방법이지만 결과 모양이 다릅니다. 이것은 다형성이지만
이 두 하위 클래스만 사용하여 그래픽을 그리는 것을 알 수 있습니다. 이를 구현하기 위해 상위 클래스를 호출하지 않습니다. 방법, 왜? ? ? 이 부모 클래스는 그래픽을 그릴 수 없기 때문에 이 부모 클래스의 그리기 메서드 구현은 쓸모가 없습니다. 이 메서드를 갖고 부모 클래스를 통해 다시 작성하려면 메서드가 필요하지 않습니다. 특정 구현.
그렇습니다. 오늘의 테마 추상 클래스를 소개합니다
위 부모 클래스의 draw 메서드는 특정 구현으로 인해 쓸모가 없으므로 작성할 필요가 없습니다. 이 역시 의 정의와 일치합니다. 설명할 수 있는 정보가 충분하면 이를 추상 클래스라고 부릅니다.
위 상위 클래스의 그리기 메서드에는 구체적인 구현이 없으므로 추상 메서드라고 부를 수 있습니다. abstract를 사용하여
public abstract void draw();
을 수정했는데 왜 오류가 보고되나요? ?
이유는 추상으로 수정된 메서드를 추상 메서드라고 부르기 때문입니다. 클래스에 추상 메서드가 있으면 클래스도 추상 클래스여야 하므로 클래스도 추상으로 수정해야 합니다.
그런데 반대로 추상클래스에는 추상메소드가 확실히 있는걸까요? ? ?
컴파일러는 오류를 보고하지 않으므로 대답은 반드시 추상 클래스가 추상 메서드를 가질 수 있는지 여부는 아닙니다.
추상 클래스를 인스턴스화할 수 있나요? ? ?
따라서 추상 클래스는 인스턴스화할 수 없습니다.
추상 클래스가 일반 클래스처럼 멤버 변수, 메서드, 생성자를 정의할 수 있나요? ? ?
추상 클래스와 일반 클래스의 차이점은 추상 클래스는 인스턴스화할 수 없다는 점이며, 멤버 변수, 멤버 메서드, 생성자 등에 대한 다른 정의는 동일합니다.
추상 클래스는 인스턴스화할 수 없는데, 그 존재 의미는 무엇인가요? ? ?
Lao Tie의 생각은 사실, 추상 클래스의 가장 큰 의미는 상속된다는 것입니다. 왜냐하면 추상 클래스는 객체를 인스턴스화할 수 없고 하위 클래스에만 의존하여 상위 클래스(즉, 추상 클래스)의 메서드를 재정의할 수 있기 때문입니다. ) 비즈니스 요구 사항을 완료합니다.
추상 클래스를 상속받는 방법은 무엇인가요? ? ? 주의할 점은 무엇인가요? ? ?
왜 상속이 이렇게 잘못되나요? ? 그 이유는 하위 클래스가 추상 클래스를 상속할 때 하위 클래스가 상위 클래스의 모든 메서드를 재정의해야 하거나 하위 클래스를 추상으로 수정해야 하기 때문입니다(추상 클래스가 추상 클래스에 상속되거나 하위 클래스가 상위 클래스의 모든 메서드를 재정의함). 추상 클래스(부모 클래스)) .
그렇습니다.
또한 부모 클래스의 메서드를 재정의하지 않고 abstract를 사용하여 수정하는 경우 이번에 이 하위 클래스를 상속하면 하위 클래스가 상위 클래스가 되고 다음 하위 클래스는 여전히 이 상위 클래스의 메서드와 이 상위 클래스의 상위 클래스 메서드를 계속 재정의합니다.
추상 메서드를 정적 메서드와 최종 메서드로 수정할 수 있나요? ? ?
하위 클래스가 상위 클래스의 메서드를 재정의해야 하고 액세스 수정 한정자를 생략할 수 있으므로 추상 메서드는 static 및 final로 수정할 수 없습니다. 기본값은 public입니다.
객체를 명확하게 설명할 수 없는 클래스를 추상 클래스라고 부릅니다.
추상으로 수정된 메서드를 추상 메서드라고 하고, 추상으로 수정한 클래스를 추상 클래스라고 합니다.
추상 메서드는 추상 클래스에 있어야 합니다. 즉, 추상 메서드가 있는 한 클래스 이름은 또한 추상을 사용해야 한다. 반대로 수정하려면 추상 클래스에 추상 메소드가 없거나 추상 메소드가 있을 수 있다.
抽象类不能实例化,除了不能实例化之外其他与普通类一样可以定义成员变量,成员方法,构造方法等。同时构造方法和类方法(被static修饰的方法)不能被abstract来修饰
抽象方法的访问修饰限定符不能是private,如果省略默认是public,同时抽象方法不能被final修饰。
子类继承抽象类的时候,子类必须重写抽象类的所有方法并且要有方法的具体实现,如果重写那子类还是抽象类,必须用abstract来修饰。
抽象类中的方法没有具体实现,要通过子类重写在子类中实现。
一个类只能继承一个抽象类
说到接口我们会想到什么呢???我一开始想到的就是充电接口插排等等,比如充电接口,只要符合那个插口的标准,我们都可以使用那个接口来进行充电。这就是把标准进行统一起来,然后大家就可以根据不同的标准来使用不同的接口,比如苹果手机与安卓手机的手机接口就是不一样的,他们就是两种不同的标准,安卓手机用安卓的接口,苹果用苹果的接口这就将标准统一起来。
而在Java中也是一样的,我们把这个标准或者可以说是一种公共的规范叫做接口,只要符合这一接口的标准我们就可以使用它。
听着这抽象的概念你可能现在还是不太明白这到底是什么,我在来拿代码举个例子:
class Animal { public String name; public int age; public void eat() { System.out.println(this.name+"吃饭***!"); } }
这里我定义了一个动物类,这个动物有名字,年龄,还有吃饭的行为。
class Animal { public String name; public int age; public void eat() { System.out.println(this.name+"吃饭***!"); } public void swim() { System.out.println("我要游泳~~~~"); } } class Fish extends Animal { }
接着我又定义了一个鱼类(子类)继承这个动物类(父类),我想让这个鱼有这个游泳的行为,但是这就会有一个问题,在父类定义了一个swim方法,接着我还要定义很多类,难道所有的类都要有这个游泳的行为么???答案是不可以的。所以我们就不能把这个swim方法定义在父类里面,那我们就可以把这个方法定义在子类(鱼类)里面,这样就符合了,但是如果我还要定义1000个动物都会游泳难道都要在自己类中写这个游泳的方法么??这样做显然是不可行的。那我们该怎么做呢??
我们可以就提供一个公共的接口,这也是一种标准,只要符合这一标准都可以使用这个接口或者可以说可以实现这一功能。
看了上面的引例我们应该接口是干什么的了,接下来我们来学一下接口的语法。
定义接口要使用interface关键字:
//创建一个接口 //创建接口要是用interface关键字 接口的命名最好是形容词其他的也可以 interface IFlying{ //这就是一个flying接口 }
接口中的成员变量:
这样会报错,接口中的成员变量都是常量,所以必须初始化,接口中的成员变量会被隐式指定为public static final 修饰的。
interface IFlying{ //接口中的成员变量默认都是被public static final修饰的常量 //这里的成员变量不可改变 public static final int a =10; }
接口中的成员方法:
interface IFlying{ //接口中的成员方法都是抽象方法,默认是public abstract //其中public abstract 可以被省略 //接口中的成员方法不能有具体的实现 public abstract void eat(); //一般就写成: //void eat(); default void sleep(){ //接口中的方法想要具体实现,要加上default修饰 } //接口中可以有静态方法的具体实现 public static void method() { System.out.println("我是静态的方法!!"); } }
接口能否实例化???
接口是不能被实例化的。
怎么使用接口???
实现的接口如下:
interface IFlying{ void eat(); } interface IRunning{ void run(); } interface ISwimming{ void swim(); } interface IClimbing{ void climb(); }
//创建一个Ant类 //利用implements关键字来实现接口 //一个类可以实现多个接口,接口之间利用逗号连接 //实现了接口必须要在接口中重写接口中的方法 //重写方法快捷键:鼠标移动到implements关键字上然后 alt+enter class Ant implements IClimbing,IRunning{ public String name; @Override public void run() { System.out.println(this.name+"要跑步"); } @Override public void climb() { System.out.println(this.name+"爬山"); } }
接口的使用时利用implements关键字与类连接,类与接口之间使用implements连接的。
一个类可以实现多个接口,多个接口之间利用逗号连接。
class Ant implements IClimbing,IRunning.的意思是类Ant可以实现两个功能,既可以爬又可以跑。
类实现接口时,必须要重写接口中的方法。如果不重写该类还是抽象类,要用abstract来修饰。
接口能否有静态方法和代码块呢???
接口中是不能有静态代码块和构造方法的。
我们这里总结一下类与接口之间的联系
类与类之间是继承关系利用extends来连接 代表子类继承了父类
类与接口之间是利用implements来连接, 代表类能实现某个功能
接口与接口之间也可以进行联系,利用extends 接口A和接口B interface A enxtends B 代表接口A拓展了接口B的功能。
这里来讲一下接口与接口之间的继承
我们利用extends关键字将两个接口连接起来,这样就实现了接口之间的继承。
例如:
interface IRunning extends IFlying{ //类IRunning拓展了IFlying的功能 void run(); //接口与接口之间继承后IRunning拓展了IFlying功能 //有了IRunning的功能的类也要重写IFlying这个方法 }
类IRunning拓展了IFlying的功能
接口与接口之间继承后IRunning拓展了IFlying功能
有了IRunning的功能的类也要重写IFlying这个方法
我们这里举一个例子:
比如我们要进行给一个学生进行排序,我们之前学过Arrays的sort方法,好我们来尝试一下这个方法对学生进排序。
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 + '}'; } } public class TestDemo { public static void main(String[] args) { Student[] student = new Student[4]; student[0] = new Student("张三",18,88); student[1] = new Student("李四",98,98); student[2] = new Student("王二麻子",8,18); student[3] = new Student("赵老八",58,38); System.out.println(Arrays.toString(student)); Arrays.sort(student); System.out.println(Arrays.toString(student)); } }
从这里发现Arrays.sort方法是比较具体的数字大小的,而我们这里比较学生这个对象并没有指定,我们究竟依靠什么来比较这个学生对象,目前这个学生有名字,分数,年龄,我们到底依靠什么比较是根据我们的需求来定,那我们要具体的比较学生对象的某一个学生怎么比较呢·???看报错信息也就是这个异常,我们需要提供这个comparable这个接口然后重写这个comparable方法。
怎样提供接口????
我们根据类要实现一个接口是利用关键字implements来连接的。
然后使用comparable这个接口,尖括号里面写上你要排序的类。
好这样我们就实现了这个接口,当然看前面那个红线就知道会有报错,这也就是当我们实现一个接口我们必须重写这个接口中的方法,然后Alt+enter重写这个接口中的方法。
好,我们就重写了这样的一个方法,比如我们要比较年龄按照升序排列:
然后调用Arrays.sort方法就可以进行排序了。
同样我们还可以根据名字排序:
由于,名字是String类型也就是引用类型所以我们要调用compareTo方法来进行比较。
同样的我们还可以根据分数来排序这个学生对象。
我们刚才使用comparable这个接口会有一个缺陷,就比如当我们已经实现按照年龄排序好了,但是有个人突然把他改成了名字比较,如果是未来做项目开发的时候,那就会给程序猿造成很大的困扰,就怕有一天别人修改了那段代码,所以我们就有了这个comparator这个比较器,我们还是把他封装起来,不用在去学生这个类中去修改。
对学生年龄排序:
class AgeComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; } }
对学生分数排序:
class ScoreComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return (int)(o1.score - o2.score); } }
对学生名字排序:
class NameComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.name.compareTo(o2.name); } }
我们还是利用Arrays.sort方法里面再加一个比较器的这个参数就可以比较了。
public static void main(String[] args) { Student[] student = new Student[4]; student[0] = new Student("张三",18,88); student[1] = new Student("李四",98,98); student[2] = new Student("王二麻子",8,18); student[3] = new Student("赵老八",58,38); System.out.println(Arrays.toString(student)); AgeComparator ageComparator = new AgeComparator(); Arrays.sort(student,ageComparator); System.out.println(Arrays.toString(student)); }
这样我们将根据什么排序,实例化对应的对象,通过对象调用重写comparator的方法就可以进行比较,不需要担心类中被修改。
我们之前学过数组中的克隆方法,就是把一个数组中的内容全部拷贝到另外一个数组中去。
今天我们学的cloneable接口可以将一个对象的属性拷贝到另外一个对象里面去。
我们创建一个人这个类,人这个类中有两个属性,一个是分数,一个是smartphone这个对象(引用类型)。
class SmartPhone{ public int money = 9999; } class Person{ public int score = 96; SmartPhone smartPhone = new SmartPhone(); } public class TestDemo { public static void main(String[] args){ Person person1 = new Person(); } }
我们现在要将这个person这个类实现cloneable接口,利用implements连接,同样的我们要重写这个cloneable这个接口中的方法。
这里我们要注意·重写cloneable这个方法,它的返回类型是object,object是Java中所有类的父类。
好,完成了接口的操作,我们接下来完成克隆的工作,我们怎么使用clone这个方法来进行克隆呢???
//浅拷贝 class SmartPhone{ public int money = 9999; } class Person implements Cloneable{ public int score = 96; SmartPhone smartPhone = new SmartPhone(); @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "score=" + score + ", smartPhone=" + smartPhone + '}'; } } public class TestDemo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(); Person person2 = (Person)person1.clone(); System.out.println(person1.smartPhone.money); System.out.println(person2.smartPhone.money); person1.smartPhone.money=9; System.out.println("===============拷贝之后================="); System.out.println(person1.smartPhone.money); System.out.println(person2.smartPhone.money); } }
原因是什么呢??画一下图理解一下
这就是浅拷贝,对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此
为浅拷贝。只要将money值进行修改两个对象的money的值都改变,没有彻底的拷贝。
//深拷贝 class SmartPhone implements Cloneable{ public int money = 9999; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "SmartPhone{" + "money=" + money + '}'; } } class Person implements Cloneable{ public int score = 96; SmartPhone smartPhone = new SmartPhone(); @Override protected Object clone() throws CloneNotSupportedException { Person tmp = (Person)super.clone(); tmp.smartPhone= (SmartPhone) this.smartPhone.clone(); return tmp; } @Override public String toString() { return "Person{" + "score=" + score + ", smartPhone=" + smartPhone + '}'; } } public class TestDemo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(); Person person2 = (Person)person1.clone(); System.out.println(person1.smartPhone.money); System.out.println(person2.smartPhone.money); person1.smartPhone.money=9; System.out.println("===============拷贝之后================="); System.out.println(person1.smartPhone.money); System.out.println(person2.smartPhone.money); } }
此时为深拷贝,进行了彻底的拷贝。对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
위 내용은 Java 추상 클래스 및 인터페이스를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!