1.抽象类
通过abstract修饰的java类就是抽象类。
1.1抽象类作用
例如:坐车收费,出租车有收费功能,公交车有收费功能,但每个交通方式具体的收费不一样,比如出租车1元/公里,公交车全程一元。
共同的是汽车收费功能,不同的是各自重写收费功能。因此我们可以理解为汽车就是一个抽象类,出租车/公交车都是汽车的子类,出租车/公交车就会从汽车中继承来收费功能然后再根据自身的实际情况,重写收费功能就可以得到属于自己的收费功能实现。
抽象类实际上就是提供同一种类型事物的公共内容,由抽象类的子类根据自身的实际情况,来实现这个抽象类提供的公共内容。这样子类就不需要创建这个公共内容,只需要继承来重写一下就好。
抽象类的子类往往都是同一种类型。
1.2 抽象类中的元素
抽象类------实例变量,静态成员变量,构造方法,实例方法,静态方法,【抽象方法】
误区:判断一个类是不是抽象类不看有没有抽象方法。抽象类可以有抽象方法也可以没有,主要看class前有没有abstract。
抽象方法格式:修饰符 abstract 返回值 名称([参数]);
注意没有方法体
例:
//抽象类
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();
}
1.3 抽象类具体用法
(1)抽象类不能new,如果需要访问抽象类中的实例元素,需要借助子类来访问。
(2)普通的java类继承了抽象类,就需要重写抽象类中的所有抽象方法,否则将这个普通的java类改成抽象类。
例:
//子类
public class TestSonClass extends TestClass{
//父类抽象类中有抽象方法,子类中需要重写抽象方法,否则报错
public void abstractmethod() {
System.out.println("子类中重写抽象方法");
}
}
测试类:
public class Main1 {
public static void main(String[] args) {
//new TestClass();报错
//借助子类访问抽象类
TestSonClass tsc=new TestSonClass();
System.out.println(tsc.id);
System.out.println(TestSonClass.name);
tsc.shili();
TestSonClass.staticmethod();
tsc.abstractmethod();
}
}
(3)抽象类可以继承其他的抽象类,可以不用重写抽象方法。
(4)利用上转型对象创建抽象类对象。
上转型对象:
子类的对象赋值给父类的变量,此时子类就向上转型成父类对象。
上转型对象不能访问子类本身的变量和方法,因为已经转型成父类了,如果需要访问子类本身的变量和方法,需要强制类型转换。
例:
//父类
public class Person {
public void methodPerson(){
System.out.println("Person类的实例方法");
}
}
//Person的子类
public class Student extends Person{
public void methodStudent(){
System.out.println("Student类的实例方法");
}
}
测试类:
public class Main2 {
public static void main(String[] args) {
//上转型对象---子类的对象赋值给父类的变量
Person per=new Student();//此时per就是父类对象了
//试着访问子类方法
//per.methodStudent;报错
//访问父类对象
per.methodPerson();//输出Person类的实例方法
//如果需要输出子类对象和方法,可以强制类型转换
Student stu=(Student)per;
stu.methodStudent();//输出Student类的实例方法
}
}
(5)抽象类对象可以访问抽象类中的实例变量、类变量、构造方法、实例方法、类方法、【抽象方法】。
例:这里只演示调抽象方法,其他调抽象类中的实例变量、类变量、构造方法、实例方法、类方法不演示
//抽象类
public abstract class TestClass {
//抽象方法
public abstract void info();
}
//子类
public class TestSonClass extends TestClass{
public void info() {
System.out.println("TestSunClass子类重写父类TestClass的抽象方法");
}
}
测试类:
public class Main3 {
public static void main(String[] args) {
//上转型对象创建抽象类
TestClass tc=new TestSonClass();//tc是抽象类
tc.info();
}
}
(6)抽象类对象访问抽象方法时候实际上访问的是子类重写以后的抽象方法。
(7)当某一个普通的java类中的方法参数是抽象类类型的时候,可以传递上转型对象,也可以是抽象类的子类对象。
例如:普通的java类
public class PuTongClass {
//当某一个普通的java类中的方法参数是父类的抽象类类型
public void testPuTong(TestClass tc){
System.out.println("PuTongClass类的实例方法");
tc.info();
}
}
测试类:
public class Main3 {
public static void main(String[] args) {
PuTongClass puc=new PuTongClass();
//puc.testPuTong(tc);报错,参数tc是抽象类,在主方法没有去创建
//回到创建抽象类,第一种利用上转型对象创建抽象类
TestClass tc1=new TestSonClass();
puc.testPuTong(tc1);
//创建抽象类,第2种利用new子类创建抽象类
TestSonClass tsc=new TestSonClass();
puc.testPuTong(tsc);
}
}
1.4 抽象类-游戏角色实例
例:
//角色父类
public abstract class JueSe {
public abstract void attack();
}
//角色子类--射手
public class SheShou extends JueSe{
public void attack() {
System.out.println("射击物理攻击");
}
}
//角色子类--法师
public class FaShi extends JueSe{
public void attack() {
System.out.println("魔法法术攻击");
}
}
//普通java类--游戏
public class Game {
public static JueSe chooseJueSe(String name){
JueSe js=null;
if(name.equals("射手")){
js=new SheShou();
}
if(name.equals("法师")){
js=new FaShi();
}
return js;
}
}
测试类:
//主方法
import java.util.Scanner;
public class YongHu {
public static void main(String[] args) {
System.out.println("请选择您的角色");
//数据输入
Scanner sc=new Scanner(System.in);
String name=sc.next();
//
JueSe js=Game.chooseJueSe(name);
js.attack();
}
}
2.接口
通过interface关键字修饰的java元素就是接口。
格式:public interface 接口名{ }
interface 接口名{ }
2.1 接口作用
为了克服java的单继承,接口可以被实现多个。
例如:收费,汽车-出租车有收费功能【1元/公里】,飞机有收费功能【全程1000元】,出租车与飞机不是同一类事物,但是有相同的功能。
接口实际上就是提供不同类型事物的公共内容,由接口的子类根据自身的实际情况,来实现这个接口提供的公共内容。这样子类就不需要创建这个公共内容,只需要继承来重写一下就好。
2.2 接口中的元素
接口中可以有类变量、静态方法、抽象方法。只有这三种,然后一定都是public修饰符,不能有其他的,可以省。
(1)接口中变量一定是public static 修饰的类变量;public static可以省略。
(2)接口中的类方法一定是public修饰的,public可以被省略;
(3)接口中的抽象方法一定是public abstract修饰的,public abstract 可以省略。
例:
//接口
public interface TestInterface {
//静态成员变量
int id=1000;//不是实例变量,因为省略了public static
static String name="zhangsan";//省略public
public int age=24;//省略static省
//实例方法
//public void method(){} //报错
//静态方法
public static void staticMethod(){}
//构造方法
//public TestInterface(){}//报错
//抽象方法
public abstract void method1();
}
测试类:
public class Main5 {
public static void main(String[] args) {
//测试接口中的变量是静态成员变量还是实例变量
//区别在于实例变量不能类名访问
System.out.println(TestInterface.id);//可以类名访问
System.out.println(TestInterface.name);//可以类名访问
//TestInterface.id=1001;//报错,说明值不能被修改,不能被修改的变量是常量
}
}
因此:修改为接口中可以有常量、静态方法、抽象方法
(1)接口中变量一定是public static final修饰的类变量;public static final可以省略。
(2)接口中的类方法一定是public修饰的,public可以被省略;
(3)接口中的抽象方法一定是public abstract修饰的,public abstract 可以省略。
2.3 接口的用法
(1)接口不能new,如果需要访问抽象方法需要借助接口子类
接口里面的变量和静态方法都是静态的,可以直接类名访问,不用创建对象,但是要访问接口里面的抽象方法,不能new,需要借助接口子类。
(2)类可以通过implements关键字去实现一个/多个接口。
(3)普通的类去实现一个/多个接口,就需要将每一个接口中的抽象方法重写,否则就需要将这个普通的类改成抽象类。
例:
public interface TestInterface {
public abstract void method1();
}
public interface DoxInterface {
//抽象方法
void abstractMethod();
}
public class PuTongClass implements TestInterface,DoxInterface{
//有抽象方法要重写
public void abstractMethod() {
}
public void method1() {
}
}
(4)抽象类去实现一个/多个接口,不需要重写接口中的抽象方法。
因为抽象类中可以有抽象方法,普通类不行
(5)接口可以继承接口,并且可以继承父接口中的所有元素。
public interface DoxInterface extends TestInterface{ }
(6)利用接口回调对象创建出接口对象
接口回调对象
①接口回调对象与上转型对象很相似,接口回调对象------接口的子类对象赋值给接口变量。
②接口回调对象只能访问接口的抽象方法,实际上访问子类重写以后的抽象方法。
③接口回调对象不能访问子类本身的方法,如果要访问就需要强制类型转换。
例:
//接口父类
public interface PersonInterface {
void info();
}
//接口子类
public class Student implements PersonInterface{
public void info() {
System.out.println("重写接口的抽象方法");
}
public void me(){
System.out.println("子类本身的方法");
}
}
public class Main6 {
public static void main(String[] args) {
//接口不能new
//new PersonInterface;报错
//利用接口回调对象创建接口对象
PersonInterface psi=new Student();//接口对象
//接口回调对象只能访问接口的抽象方法,实际上访问子类重写以后的抽象方法
psi.info();
//接口回调对象不能访问子类本身的方法,如果要访问就需要强制类型转换
//psi.me();报错
Student st=(Student)psi;
st.me();
}
}
(7)当某一个普通的java类中的方法参数是接口类型的时候,可以传递接口回调对象,也可以是接口的子类对象。
3.抽象类和接口区别
抽象类 | 接口 |
abstract class | interface |
继承关系 Extends 单继承 | 实现关系 implements实现一个/多个接口 |
提供同类型事物的公共内容 | 提供不同类型事物的公共内容 |
有实例变量、类变量、构造方法、实例方法、类方法 | 有类变量(此处为常量)、JDK8.0类方法、抽象方法 |
抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public,不可以使用其它修饰符 |
4. 四个关键字static this super final
4.1 static静态修饰符
(1)被static修饰的变量是静态成员变量,可以类名访问,也可以对象访问;
(2)被static修饰的方法是静态方法,可以类名访问,也可以对象访问;
(3)同一个类中静态方法不能访问实例元素,this不能出现。
4.2 this当前类对象
(1)出现在哪个类中就表示哪个类的对象;
(2)在当前类中的构造方法/实例方法中访问当前类中的变量和方法,可以省略。
(3)在当前类中的构造方法/实例方法中访问被隐藏的成员变量时不能省略。
4.3 super父类的对象
(1)出现在子类中的构造方法第一句时,super()父类无参数构造方法/super(参数)父类有参数构造方法;
(2)出现在子类中的实例方法是,表示访问父类的变量/方法;
(3)访问被隐藏的父类变量,super.变量名称,此时这个super表示父类的对象。一般指访问没有重写之前的父类方法,super.方法名称([参数]),此时这个super表示父类的对象
4.4 final终极修饰符
(1)被final修饰的类,不能被继承,没有子类;
public final class TestClass {
}
//错误:The type TestSunClass cannot subclass the final class TestClass
public class TestSunClass extends TestClass{
}
(2)被final修饰的变量,就是常量,不能被重新赋值;
public class Main {
public static void main(String args[]){
final String name="zhangsan"; //局部变量
System.out.println("name=="+name);
//错误:被final修饰的变量,就是常量,不能被重新赋值
//name="lisi";
System.out.println("name=="+name);
}
}
(3)被final修饰的方法,不能被重写。
public class TestClass {
public final void info(){
System.out.println("TestClass类的实例方法");
}
}
public class TestSunClass extends TestClass{
/*
被fianl修饰的方法,不能被重写。
public void info(){
System.out.println("重写从父类继承的info方法");
}
*/
}