抽象类和接口
1.抽象类
类–用来描述具有共同性质的一组事物的自定义复合数据类型,class关键字创建
public class Hello{} — 类
抽象类–通过abstract 修饰的java类就是。
public abstract class Hello{}—抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2.为什么要有抽象类?
例如:坐车收费,出租车有收费功能【1元/公里】,公交车有收费功能【全程1元】。
出租车/公交车----汽车—收费功能
出租车 extends 汽车 —重写收费功能—【1元/公里】
公交车 extends 汽车 —重写收费功能— 【全程1元】
我们可以理解为汽车就是一个抽象类,出租车/公交车都是汽车的子类,出租车/公交车就会从汽车中继承来收费功能然后在根据自身的实际情况,重写收费功能就可以得到属于自己的收费功能实现。
抽象类的子类往往都是同一种类型。
抽象类实际上就是提供同一种类型事物的公共内容,由抽象类的子类根据自身的实际情况,来实现这个抽象类提供的公共内容。这样子类就不需要创建这个公共内容,只需要继承来重写一下就好。
3.抽象类中可以有哪些元素?
类–实例变量,静态成员变量,构造方法,实例方法,静态方法
抽象类–实例变量,静态成员变量,构造方法,实例方法,静态方法,【抽象方法】
误区:判断一个类是不是抽象类不看有没有抽象方法。
方法基本格式:修饰符 返回值 名称([参数]){方法体}
实例方法:修饰符 返回值 名称([参数]){方法体}
静态方法:修饰符 static 返回值 名称([参数]){方法体}
构造方法:修饰符 类名([参数]){方法体}
抽象方法:修饰符 abstract 返回值 名称([参数])
抽象方法–使用abstract修饰的没有方法体的方法
抽象类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
例如:
package com.wangxing.zyb1;
public abstract class TestClass{
public int id=1001;//实例变量
public static String name="zhangsan";//静态成员变量
public TestClass() {
System.out.println("构造方法");
}
public void shili() {
System.out.println("实例方法");
}
public static void staticmethod() {
System.out.println("静态方法");
}
//抽象方法--使用abstract修饰的没有方法体的方法
//抽象方法:修饰符 abstract 返回值 名称([参数])
public abstract void abstractmethod();
}
package com.wangxing.zyb1;
public class TestSunClass extends TestClass{
@Override
public void abstractmethod() {
}
}
package com.wangxing.zyb1;
public class Main1 {
public static void main(String[] args) {
TestSunClass tsc1=new TestSunClass();
System.out.println(tsc1.id);
System.out.println(TestSunClass.name);
tsc1.shili();
TestClass.staticmethod();
}
}
4.抽象类的具体用法
1.抽象类不能new,借助子类访问抽象类中的实例元素。
2.普通的java类继承了抽象类,就需要重写抽象类中的所有抽象方法,否则将这个普通的java类改成抽象类。
3.抽象类可以继承其他的抽象类,可以不用重写抽象方法。
4.利用上转型对象创建出抽象类对象
5.抽象类对象可以访问抽象类中的实例变量、类变量、构造方法、实例方法、类方法、【抽象方法实际上是子类重写以后的方法】。
6.当某一个普通的java类中的方法参数是抽象类类型的时候,可以传递上转型对象,也可以是抽象类的子类对象。
例如:
package com.wangxing.zyb3;
public abstract class TestClass {
//抽象方法
public abstract void info();
}
package com.wangxing.zyb3;
public class TestSunClass extends TestClass{
public void info() {
System.out.println("TestSunClass子类重写父类TestClass的抽象方法");
}
}
package com.wangxing.zyb3;
public class Person {
public void testPerson(TestClass tc) {
System.out.println("Person类的实例方法");
tc.info();
}
}
package com.wangxing.zyb3;
public class Main {
public static void main(String[] args) {
//抽象类不能new
//new TestClass();
//如果我们需要创建出抽象类的对象,就需要借助上转型对象
//上转型对象--子类的对象赋值给父类的变量
TestClass tc1=new TestSunClass();
tc1.info();
}
}
package com.wangxing.zyb3;
public class Main {
public static void main(String[] args) {
Person per1=new Person();
TestClass tc1=new TestSunClass();//上转型对象
per1.testPerson(tc1);
TestSunClass tsc=new TestSunClass();//子类对象
per1.testPerson(tsc);
}
}
5.上转型对象
上转型对象–子类的对象赋值给父类的变量,此时子类对象就向上转型成父类对象
上转型对象不能方法子类本身的变量和方法,如果我们需要访问子类本身的变量和方法,需要通过强制类型转换
例如:
package com.wangxing.zyb2;
public class Person {
public void testPerson() {
System.out.println("Person类的实例方法");
}
}
package com.wangxing.zyb2;
public class Student extends Person{
public void testStudent() {
System.out.println("Student类的实例方法");
}
}
package com.wangxing.zyb2;
public class Main {
public static void main(String[] args) {
//上转型对象--子类的对象赋值给父类的变量,此时子类对象就向上转型成父类对象
Person per=new Student();
per.testPerson();
//上转型对象不能方法子类本身的变量和方法
//per.testStudent();
//如果我们需要访问子类本身的变量和方法,需要通过强制类型转换
Student stu=(Student)per;
stu.testPerson();
stu.testStudent();
}
}
利用上转型对象创建出抽象类对象
6.卖水果实例
package com.wangxing.zyb4;
public abstract class ShuiGuo {
public abstract void eat();
}
package com.wangxing.zyb4;
public class PingGuo extends ShuiGuo{
@Override
public void eat() {
System.out.println("我是苹果");
}
}
package com.wangxing.zyb4;
public class XiGua extends ShuiGuo{
@Override
public void eat() {
System.out.println("我是西瓜");
}
}
package com.wangxing.zyb4;
public class ShangRen {
public static ShuiGuo sellShuiGuo(String name) {
ShuiGuo sg=null;
if(name.equals("苹果")) {
sg=new PingGuo();
}
if(name.equals("西瓜")) {
sg=new XiGua();
}
return sg;
}
}
package com.wangxing.zyb4;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("你好需要什么");
Scanner input=new Scanner(System.in);
String name=input.next();
ShuiGuo sg=ShangRen.sellShuiGuo(name);
sg.eat();
}
}
1.接口
通过interface关键字修饰的java元素就是接口。
格式:public interface 接口名{}
interface 接口名{}
2.为什么要有接口?
为了克服java的单继承,接口可以被实现多个
例如:收费,出租车有收费功能【1元/公里】,飞机有收费功能【全程1000元】
出租车与飞机不是同一类事物,但是有相同的功能
接口实际上就是提供不同类型事物的公共内容,由接口的子类根据自身的实际情况,来实现这个接口提供的公共内容。这样子类就不需要创建这个公共内容,只需要继承来重写一下就好。
3.接口中的元素
接口中可以有常量、静态方法、抽象方法。
1、接口中变量一定是 public static final修饰的常量。
2、接口中的静态方法一定是public修饰的,public可以被省略。
3、接口中的抽象方法一定是public abstract修饰的,public abstract可以省略
例如:
package com.wangxing.zyb5;
public interface TestInterface {
//静态成员变量
//接口中变量一定是 public static final修饰的常量。
int id=1001;
static String name="zhangsan";
public int age=23;
//静态方法
//接口中的静态方法一定是public修饰的,public可以被省略。
static void staticMethod(){}
//抽象方法
//接口中的抽象方法一定是public abstract修饰的,public abstract可以省略
void abstractMehod();
}
package com.wangxing.zyb5;
public class Main {
public static void main(String[] args) {
System.out.println(TestInterface.id);
System.out.println(TestInterface.name);
System.out.println(TestInterface.age);
TestInterface.staticMethod();
}
}
4.接口的用法
1.接口不能new,如果需要访问抽象方法需要借助接口子类
2.类可以通过implements关键字去实现一个/多个接口
3.普通的类去实现一个/多个接口,就需要将每一个接口中的抽象方法重写,否则就需要将这个普通的类改成抽象类.
4.抽象类去实现一个/多个接口,不需要重写接口中的抽象方法。
5.接口可以继承接口,并且可以继承父接口中的所有元素.
6.利用接口回调对象创建出接口对象
7.当某一个普通的java类中的方法参数是接口类型的时候,可以传递接口回调对象,也可以是接口的子类对象。
package com.wangxing.zyb5;
public class Person implements TestInterface,DoxInterface{
//重写DoxInterface中的抽象方法
@Override
public void docinfo() {
}
//重写TestInterface中的抽象方法
@Override
public void abstractMehtod() {
}
}
public interface DoxInterface extends TestInterface{
//抽象方法
void docinfo();
}
package com.wangxing.zyb6;
public class Person {
public static void Test(TestInterface hello) {
hello.info();
}
}
package com.wangxing.zyb6;
public class Main {
public static void main(String[] args) {
//接口不能new
//new TestInterface();
//接口回调对象--接口的子类对象赋值给接口变量
TestInterface ti1=new TestSunClass();
//接口回调对象只能访问接口的抽象方法,实际上访问子类重写以后的抽象方法
ti1.info();
//接口回调对象不能访问子类本身的方法,如果要访问就需要强制类型转换
ti1.test1();
TestSunClass tc=(TestSunClass)ti1;
tc.test1();
}
}
5.接口回调对象
接口回调对象与上转型对象很相似
接口回调对象–接口的子类对象赋值给接口变量
1.接口回调对象只能访问接口的抽象方法,实际上访问子类重写以后的抽象方法
2.接口回调对象不能访问子类本身的方法,如果要访问就需要强制类型转换
例如:
package com.wangxing.zyb6;
public class TestSunClass2 implements TestInterface{
@Override
public void info() {
System.out.println("ceshi");
}
}
package com.wangxing.zyb6;
public class Main {
public static void main(String[] args) {
Person Person1=new Person();
Person1.Test(new TestSunClass());
Person1.Test(new TestSunClass2());
}
}
抽象类与接口的区别?
抽象类 | 接口 |
---|---|
abstract class | interface |
extends 一个 | implments 一个/多个 |
提供同类型事物的公共内容 | 提供不同类型事物的公共内容 |
抽象类中的元素实例变量、类变量、构造方法、实例方法、类方法、【抽象方法】 | 接口中可以有类变量、JDK8.0类方法、抽象方法。且都是public修饰符修饰的 |
抽象方法可以有页可以没有 | 接口中大部分都是抽象方法 |
关键字
1.static 静态修饰符
1.被static修饰的变量是静态成员变量,可以类名访问,也可以对象访问
2.被static修饰的访问是静态方法,可以类名访问,也可以对象访问
3.同一个类中静态方法不能访问实例元素,this不能出现。
2.this 当前类对象
1.出现在哪个类中就表示哪个类的对象
2.在当前类中的构造方法/实例方法中访问当前类中的变量和方法,可以省略。
3.在当前类中的构造方法/实例方法中访问被隐藏的成员变量时不能省略。
3.super 父类的对象
1.出现在子类中的构造方法第一句时,super()父类无参数构造方法/super(参数)父类有参数构造方法。
2.出现在子类中的实例方法是,表示访问父类的变量/方法,访问被隐藏的父类变量,super.变量名称,此时这个super表示父类的对象,一般指访问没有重写之前的父类方法,super.方法名称([参数]),此时这个super表示父类的对象
4.final 终极修饰符
1.被fianl修饰的类,不能被继承,没有子类
public final class TestClass {
}
//错误:The type TestSunClass cannot subclass the final class TestClass
public class TestSunClass extends TestClass{
}
2.被fianl修饰的变量,就是常量,不能被重新赋值
package com.wangxing.test7;
public class Main {
public static void main(String args[]){
final String name="zhangsan"; //局部变量
System.out.println("name=="+name);
//错误:被fianl修饰的变量,就是常量,不能被重新赋值
//name="lisi";
System.out.println("name=="+name);
}
}
3.被fianl修饰的方法,不能被重写。
public class TestClass {
public final void info(){
System.out.println("TestClass类的实例方法");
}
}
public class TestSunClass extends TestClass{
/*
被fianl修饰的方法,不能被重写。
public void info(){
System.out.println("重写从父类继承的info方法");
}
*/
}