0


(JAVA)类与对象(进阶)

(JAVA)类与对象(进阶)

目录

一、包

1. 包的简介

  1. 每个包对应一个文件夹,文件夹里还可以有子类文件夹,就是子包
  2. 当你需要用到包的概念时,需要在.java文件的第一条语句,声明该文件是在什么包下
packagelearn.java_.test;publicclassTest{}

在这里插入图片描述

2. 包的使用

  1. 这时候可能有朋友疑问了:为什么不把文件路径写全呢?我的理解:你声明该文件的第一个包名为learn,那么在当你需要使用Test类时,只需要把文件夹learn直接复制到你使用的位置,就可以使用了。因为前面没写的部分,会默认在你使用的当前目录下去找learn\java_\test
  2. 示例:importlearn.java_.test.Test;publicclass paper {publicstaticvoidmain(String[] args){Test t1 =newTest();}}

在这里插入图片描述 在这里,在paper类中使用

import learn.java_.test.Test;

来引包,会在paper.java所在目录下即src中找到

learn\java_\test

下的Test.java文件。当然如果把.Test改为.*是引入该test包下所有的文件。

  1. 这里思考一下,既然上面示例中import会找到Test类,那么为什么我们还要再声明package learn.java_.test;呢?因为他们的先后顺序不要搞错了,其实只有当你在该Test.java文件的第一条语句声明package learn.java_.test;后,才能在paper类中import learn.java_.test.Test;成功。因为如果在该Test.java文件没有使用package语句声明类所在的包时,java默任包的路径为当前文件夹,例如:在paper类中使用Test类,显然paper类的当前文件夹src中并没有Test类,因此会报错的。
  2. 在同一包中的类默认情况下可以互相访问

二、🐯继承

1. 简介

  • 一个子类只能有一个父类,而一个父类可以有多个子类。
  • 父类实际上是所有子类的公共成员的集合。
  • 被继承的类称为父类或者超类,由继承而得到的类称为子类
  • 使用关键字extends,示例://A继承了BpublicclassAextendsB{}classB{}

2. 使用

  • 子类会继承父类可访问的成员变量和方法,可以直接通过子类对象来调用。
  • 示例:publicclassAextendsB{publicstaticvoidmain(String[] args){A a =newA();//访问父类的成员System.out.println(a.b); a.b();}}classB{int b =0;publicvoidb(){System.out.println("B");}}

3. super

  • super是在子类方法中使用,来代表所继承的父类的引用。
  • 用于在子类方法中访问父类的属性、方法,但不能访问private所修饰的父类成员。
  • 使用方法:super.变量名; super.方法;示例:publicclassAextendsB{voidinB(){System.out.println(super.b);super.isB();}}classB{int b;voidisB(){}}

4. 构建方法

  • 在执行子类的构造方法前,会先自动调用父类无参构造方法
  • 如果父类没有无参构造器,则必须在子类的构造器中的第一条语句使用super来初始化父类 示例:publicclassAextendsB{publicA(int b){//调用B中的public B(int b)super(b);}}classB{int b;publicB(int b){this.b = b;}}
  • 使用方法:super(参数列表)

5.🐻方法重写

  • 也称方法覆盖(override)
  • 在子类中如果有一个方法,其方法名返回类型参数都和父类中的某一方法一样,那么该子类方法就重写了父类同名方法的功能
  • 示例:publicclassAextendsB{//重写了B的say方法voidsay(){System.out.println("A");}}classB{voidsay(){System.out.println("B");}}
  • 重写的方法的返回类型可以和父类方法一样,或者是父类返回类型的子类
  • 👿重写的方法的访问权限可以比父类的大,但是不能比父类的小。如:示例中第3行省略的访问修饰符可以改成public,但是不能是protected
  • 子类中不能重写父类中有finalstatic所修饰的方法。

对于成员变量没有重写的概念。

6. 对象的多态

  • 一个对象的编译类型运行类型可以不一致
  • 编译类型是在定义时变量名前的类型,不能改变
  • 运行类型是创建对象时new的类型,可以更改。
  • 如:publicclassAextendsB{publicstaticvoidmain(String[] args){B b =newA();}}classB{}对象b的编译类型是B,而运行类型是A

6.1 向上转型

  • 父类的引用指向了子类的对象,父类类型 引用名 = 子类对象
  • 如:publicclassAextendsB{publicstaticvoidmain(String[] args){//父类的引用指向了子类的对象B b =newA(); b =newC();}}classB{}classCextendsB{}
  • 将子类对象,看作父类对象。因此该变量只能访问父类的成员,对于子类重写的方法,有覆盖的作用在在这里插入图片描述

6.2 向下转型

  • 解决向上转型后,不能访问子类特有的成员。通过向下转型,来将父类对象通过强制转换为子类类型。
  • 子类类型 引用名 = (子类类型)父类引用;publicclassTest{publicstaticvoidmain(String[] args){B b =newA();System.out.println(b.boy);//向下转型System.out.println(((A)b).apple );A a =(A) b;System.out.println(a.apple);}}classAextendsB{int apple =1;}classB{int boy =0;}

6.3 instanceof

对象运算符 instanceof

  • 使用:引用名 instanceof 类型
  • 作用:如果该引用的对象的运行类型是该类型或该类型的子类型,返回true,否则返回false在这里插入图片描述

7. 🔹练习

下面代码执行的结果是什么?

publicclassTest{publicstaticvoidmain(String[] args){B b =newA();System.out.println(b.sum());System.out.println(b.sum1());}}classAextendsB{int i =20;publicintgetI(){return i;}}classB{int i =10;publicintsum(){returngetI()+10;}publicintsum1(){return i+10;}publicintgetI(){return i;}}

结果:在这里插入图片描述

  • 对于b.sum(),首先访问到class B中的sum()方法,在sum()方法中有一个getI()方法,对于getI()的访问,其实在向下引用中,因为class A中的getI()是方法重写,该子类方法就重写了父类同名方法的功能,因此调用的是class A中的getI(),返回 20 20 20。因此sum()的结果是 20 + 10 = 30 20+10 = 30 20+10=30。
  • 对于b.sum1(),就直接是 10 + 10 = 20 10+10 = 20 10+10=20​。因为成员方法没有重写的概念

8. Object类

  • Object类java.lang类库中的一个类,所有的类都是直接或间接继承该类。即Object类是所有类的源
  • 如果一个类没有使用extends关键字,该类就默认为Object类的子类。

8.1 equels()

该equels()是Object类中所定义的方法,而Object类是所有类的父类,因此任何类都可以直接使用该方法。

  • 声明:public boolean equals(Object obj)
  • 作用:判断两个引用所指向的是否为同一个对象
  • 示例:在这里插入图片描述
  • 判断方法作用==可以判断基本类型(值是否相等)、引用类型(是否为同一对象[地址])equals()判断引用类型(是否为同一对象[地址])
  • 方法重写如:在java.lang.String类中,就将equals()进行方法重写在这里插入图片描述如果String类型的对象使用equals(),则判断的是字符串的值。因为子类方法重写了equles()的功能。

8.2 toString()

同样也是

java.lang.Object

类中定义的方法,可以直接使用

  • 声明:public String toString()
  • 默认返回:全类名+@+哈希值的十六进制
  • 当输出一个对象时,toString()方法会被默认调用。
  • 示例:在这里插入图片描述
  • 子类往往会重写toString(),在IDEA中,可以使用快捷键:alt+insert在这里插入图片描述

然后选择toString(),默认的是把属性的值输出。

9. final

9.1 简介

  • final做为修饰符,表明最终的意思,即不可修改。

9.2 属性

  • 如果用final来修饰成员变量,则说明该成员变量为常量。必须有初始化,且不能修改了
  • 对其初始化有三种方式://方式1:在定义时初始化classA{finalint a =10;}//方式2:在构造器中初始化classB{finalint b;B(int b){this.b = b;}}//方式3:在代码块中初始化classC{finalint c;{ c =10;}}

9.3 方法

  • 如果用final来修饰成员方法,则表明该方法不能被子类所重写,可提高安全性

9.4 类

  • 如果用final来修饰,则该类不能继承,既不能做为父类,也不能做为子类。

四、抽象类

1.简介

  • 使用修饰符abstract所修饰的类
  • 抽象类是专门作为父类而创建的,它的作用类似于__模板__
  • 目的是根据抽象类的格式来创建子类,再由其子类来创建对象。
  • 因此抽象类不能创建实例化对象(new)

2.💫抽象方法

  • 使用修饰符abstract所修饰的方法
  • 使用:[其他修饰符] abstract 返回类型 方法名(参数列表);抽象方法没有{}(方法体)
  • 示例://抽象类BabstractclassB{//抽象方法boy()publicabstractvoidboy();}
  • 抽象类中可以没有抽象方法,但是有抽象方法的类必须声明为抽象类
  • 抽象类的子类必须实现父类中的所有抽象方法,或者子类也是一个抽象类示例:abstractclassB{publicabstractvoidboy();}classAextendsB{//实现父类中的抽象类publicvoidboy(){}}//子类C也是一个抽象类abstractclassCextendsB{}
  • 抽象方法不能使用private、final、static来修饰,因为该关键字修饰的方法都不能重写。

3.其他

  • abstract只能用来修饰类和方法
  • 普通类有的成员,抽象类都可以有,因为抽象类的本质还是类只是不能实例化对象

五、接口

1.简介

  • 使用关键字interface来定义接口
  • //接口的定义[public/无]interface 接口名{}
  • 接口也不能创建实例化对象(new)

2.🎏接口的成员

  • 属性,实际上是静态常量interfaceA{//属性a,必须初始化int ONEA =100;}对于接口的属性都是public static final修饰的,当省略修饰符,系统会默认。 如:int a=100;实际上是public static final int a=100;
  • 抽象方法interfaceA{//抽象方法apple()voidapple();}对于抽象方法,当省略修饰符,系统会默认为public abstract。如:上例,实际上是public abstract void apple();
  • 在定义接口时,一般都省略属性和抽象方法的修饰符
  • 静态方法interfaceA{//静态方法staticvoidgo(){System.out.println("接口A中的静态方法");}}接口中的静态方法,不能被子接口和实现类所继承,但可以通过**接口名.静态方法名()**来访问
  • 默认方法interfaceA{//默认方法defaultvoidto(){System.out.println("接口A中的默认方法");}}接口中的默认方法用default修饰符定义,为达到一种在接口中定义与类中普通成员方法相似的效果。
  • 接口中的方法都是public的,可以在定义时省略。

3.接口的实现

  • 利用接口来创建新类的过程是接口的实现
  • 接口的实现类似于继承,只不过是使用关键字implenments来实现接口
  • 普通类实现接口必须实现接口所有的抽象方法,而抽象类则可不必。//接口AinterfaceA{voidapple();}//类B实现接口AclassBimplementsA{//实现抽象方法apple()publicvoidapple(){}}//抽象类C实现接口AabstractclassCimplementsA{}
  • 因为接口中的方法都是public,所有在实现抽象方法时,需要显示的使用public修饰符,实现的方法不能缩小接口中该方法的访问控制范围(和方法重写一样)。

3.1用接口实现类的多重继承

  • java不支持类的多重继承,但是可以利用接口间接的解决这个问题
  • 一个类可以实现多个接口,它们间用,分隔interfaceA{}interfaceB{}classCimplementsA,B{}
  • 接口中的常量、抽象方法和默认方法可以被实现该接口的类所继承。但不能继承接口中的静态方法。在这里插入图片描述

3.2名字冲突

  • 一般指一个类实现多个接口,不同接口中相同的默认方法引起的冲突interfaceA{//常量appleint apple =0;//默认方法defaultvoidto(){}//抽象方法voidplay();}interfaceB{//常量appleint apple =10;//默认方法defaultvoidto(){}//抽象方法voidplay();}classCimplementsA,B{//重写to() //这里没有defaultpublicvoidto(){//A.super.to();}//实现play()publicvoidplay(){}voiduse(){System.out.println(A.apple);System.out.println(B.apple);}}
  • 当实现到两个相同的默认方法时,可以通过重写来解决冲突。而对于抽象方法,因为后续也是要(实现)的,也会达到重写的效果,因此没有冲突。对于接口属性,可以通过接口名.属性来避免冲突。

4.接口的多态

  • 用一个类实现一个接口后,该类和该接口的关系类似于继承。
  • 如: 二、继承 6。对象的多态
  • 可以使用接口的引用来指向子类对象。publicclassTest{publicstaticvoidmain(String[] args){//父接口引用a指向子类对象A a =newB(); a.apple();}}interfaceA{voidapple();}classBimplementsA{//实现抽象方法apple()publicvoidapple(){}//B特有的boy()voidboy(){}}
  • 也有相同的向下转型B b =(B)a;b.boy();

5. 接口的继承

  • 和类相似,接口也可以继承,使用extends来表明继承关系
  • 一个接口可以继承多个父接口,它们间用,分隔interfaceA{}interfaceB{}//接口C继承接口A和BinterfaceCextendsA,B{}
  • 接口会继承父接口中的常量、抽象方法和默认方法,但不能继承父接口中的静态方法。
  • 接口不能和类通过extends产生关系
  • 如果遇到名字冲突问题可参考2.接口的实现中的解决方法

六、内部类

  • 内部类是定义在类中的类,也称为嵌套类,包含内部类的类称为外部类
  • 内部类可以看作外部类的一个成员,与一般类相同,只是定义置于一个类的内部。

1.分类

  • 定义在外部类局部位置上,相当于局部变量的地位a.局部内部类(有类名)b.匿名内部类(没类名)
  • 定义在外部类的成员位置,相当于类成员的地位a.成员内部类(无static)b.静态内部类(有static)

2. 局部内部类

  • 示例:classOuter{//外部类int a =1;voidOutf(){}publicvoidOutf1(){//一般在方法里定义classInner{//内部类int a =2;publicvoidInf(){//可以直接访问外部类的成员Outf();//Outer.this本质就外部类的对象System.out.println(Outer.this.a);//1//就近原则System.out.println(a);//2}}//使用:Inner inner =newInner();inner.Inf();}}
  • 在内部类里可以直接访问外部类的所有成员,对于成员重名问题,默认遵循就近原则,然后如果是访问外部类的成员,可以使用外部类名.this.成员来访问
  • 不能有访问修饰符(public、private和protected)。因为它相当于一个局部变量
  • 作用域:在定义它的方法或代码块的{}范围中
  • 使用:在作用域的{}范围内,先创建对象,再访问。

3.🔑匿名内部类

  • 如果某个类的对象只用一次,则可在定义类的同时就创建该类的对象。
  • 这种定义类的方法不取名字,所以称为匿名内部类,类名由系统分配。
  • 语法:返回的是一个对象的引用new 类/接口(参数列表){ 类体};
  • 其中类/接口,是匿名内部类所继承的类实现的接口,类也可以是抽象类,但都只能用一个。
  • 示例:classOuter{//外部类int a =-1;publicvoidf(){//定义匿名内部类//(100)会调用父类的构造器Father father =newFather(100){//方法重写publicvoidshow(){System.out.println(Outer.this.getClass()+" a="+Outer.this.a);System.out.println(this.getClass()+" a="+a);}};//使用该匿名类的对象 father.show();}}classFather{int a;//构造器publicFather(int a){this.a = a;}publicvoidshow(){}}
  • 在这里插入图片描述可以发现father的运行类型是class Outer$1这就是系统自动分配的匿名内部类的类名
  • 匿名内部类也可以直接访问外部类的所有成员。如果名字相同,遵循就近原则,此时访问外部类成员可以使用外部类名.this.成员
  • 作用域: 在定义它的方法或代码块的范围中
  • 不能有修饰符,因为相当于一个局部变量。不能定义构造器,因为没有名字。
  • 匿名内部类,可以当做实参传递publicclassTest{publicstaticvoidmain(String[] args){A a =newA();//直接传递一个实现接口B的匿名内部类a.Go(newB(){//实现抽象方法go()publicvoidgo(){System.out.println("go");}});}}classA{publicvoidGo(B b){ b.go();}}interfaceB{voidgo();//抽象方法}

4. 成员内部类

  • 示例:classOuter{//外部类int a =100;publicvoidOutf(){}//成员内部类,定义在外部类成员位置classInner{int a =9;publicvoidInf(){//可直接访问外部类的成员Outf();System.out.println(Outer.this.a);}}publicvoidOutf1(){//使用成员内部类Inner inner =newInner();System.out.println(inner.a);}}
  • 在外部类外使用该内部类publicclassTest{publicstaticvoidmain(String[] args){//创建外部类对象Outer outer =newOuter();//创建该外部类对象的内部类对象Outer.Inner inner =outer.newInner();}}
  • 成员内部类可以直接可以直接访问外部类的所有成员。如果名字相同,遵循就近原则,此时访问外部类成员可以使用外部类名.this.成员
  • 可以添加访问修饰符(public、默认、protected、private),相当于一个成员

5. 静态内部类

  • 示例:classOuter{//外部类staticint a =100;staticint b =10;publicvoidOutf(){}//静态内部类staticclassInner{staticint b =9;voidInf(){//可直接访问外部类的静态成员System.out.println(a);//如果重名,就近原则,(外部类名.成员)System.out.println(b);System.out.println(Outer.b);//对于外部类的非静态成员的访问Outer outer =newOuter();outer.Outf();}}//静态内部类的使用publicvoidOutf1(){//静态内部类的静态成员System.out.println(Inner.b);//非静态成员,创建对象,再访问Inner inner =newInner();inner.Inf();}}
  • 在外部类外访问该静态内部类publicclassTest{publicstaticvoidmain(String[] args){//访问静态内部类的静态成员System.out.println(Outer.Inner.b);//访问静态内部类的非静态成员:先创建,在访问Outer.Inner inner =newOuter.Inner();inner.Inf();}}
  • 成员内部类可以直接可以直接访问外部类的静态成员。如果名字相同,遵循就近原则,此时访问外部类静态成员可以使用外部类名.成员
  • 可以添加访问修饰符(public、默认、protected、private),相当于一个成员

七、枚举

1.简介

  • 对于某一个变量只有几种固定取值时,常声明为枚举类型。如:季节。
  • 语法:使用关键字enum声明枚举类型[修饰符]enum 枚举类型名 { 枚举成员 方法}
  • 枚举成员也称枚举常量或枚举值,不能重名,用,分隔,都默认被final public static修饰
  • 这里枚举类型名,也是枚举成员的数据类型,所有枚举成员也称为枚举实例或枚举对象
  • 枚举是一种特殊的类,会默认继承java.lang.Enum,因此不能再继承其他类,但可以实现接口。
  • 非抽象的枚举会默认使用final修饰,因此不能派生子类
  • 枚举的所有枚举成员必须放在枚举体的第一条语句

2.不包含方法的枚举

  • 因为自动继承Enum类,所以可以直接使用Enum类中的方法
  • 方法功能public static enumtype[] values()返回枚举类型的数组,包含所有枚举成员,按声明顺序存储public static enumtype valueOf(String str)返回名称为str的枚举成员public String toString()返回枚举成员的名称public final int ordinal()返回枚举成员的序号(从0开始)public final String name()返回枚举常量的名称…………
  • 在这里插入图片描述

3. ✨包含属性和方法的枚举

  • 如果枚举成员,需要有更丰富的内容,这时就可以赋予他们属性和方法
  • 示例://定义枚举类型SeasonenumSeason{//声明4个枚举成员SPRING("春"),SUMMER("夏"),AUTUMN("秋"),WINTET("冬");//属性privateString name;//构造器,默认是privateSeason(String name){this.name = name;}//重写toString()publicStringtoString(){return name;}voidplay(){System.out.println(name+"天就要去玩耍");}}
  • 在这里插入图片描述
  • 枚举的构造方法只能是private修饰的,可以省略。
  • 因此枚举成员必须在定义时就加上(参数列表),如果有无参构造器,则可省略()

🦀🦀观看。

待续~~


本文转载自: https://blog.csdn.net/qq_60880296/article/details/125311379
版权归原作者 异样旧日 所有, 如有侵权,请联系我们删除。

“(JAVA)类与对象(进阶)”的评论:

还没有评论