Java基本语法(五)—— 面向对象(中)

233 阅读8分钟

1.继承

用法:class A extends B{},其中A是子类、B是父类

一旦继承后,子类获取到了父类的属性和方法。

对于父类中的private的属性或方法,由于封装性的原因子类不能直接调用这种私有属性或方法

关于继承的规定:

  • 一个class可以被多个subclass继承;一个类只能有一个父类(单继承)
  • 类可以多层继承(C extends B、B extends A,A是C的间接父类,B是C的直接父类)
  • 子类继承父类后,就继承了直接父类、所有间接父类中声明的属性和方法

关于object:如果一个class没有显式地声明其父类,则此类继承java.lang.object


2.方法的重写(override)

定义:在子类中可根据需要对从父类中继承的方法进行改造,也叫方法的覆盖、重置。在程序执行时,子类的方法将覆盖父类的方法。

重写以后,调用子类对象中和父类同名同形参的方法,实际执行的是子类中覆盖后的方法。

要求:

  1. 方法名、形参列表都要相同

  2. 子类重写的方法的权限修饰符不小于父类中被重写方法的权限修饰符

    • 特殊情况:子类不能重写父类中private的方法
  3. 返回值类型:

    • 父类中被重写的方法返回值类型为void,子类中重写的方法返回值类型也只能为void
    • 父类中被重写的方法返回值类型为基本数据类型,子类中重写的方法返回值类型也只能为相同类型(比如父类为double,子类也只能是double)
    • 父类中被重写的方法返回值类型为A类,子类中重写的方法返回值类型可以是A类或者A类的子类
  4. 子类重写的方法抛出的异常类型不大于父类中被重写的方法抛出的异常类型。

子类和父类中同名同参数的方法,要么都是static的(不是重写),要么都是非static的


3.四种访问权限修饰符

看视频:273.尚硅谷面向对象(中)-测试4种不同的权限修饰哔哩哔哩_bilibili


4.关键字super

super可以理解为:父类的;super可以用来调用属性、方法、构造器

super的使用:

  • 在子类的方法或构造器中,使用"super.属性"、"super.方法"的方式,显式地调用父类中声明的声明或属性,但是通常情况下省略super
  • 当子类和父类中定义了重名的属性时,想要在子类中调用父类中声明的属性,必须显式地使用"super.属性"进行调用(方法也是如此)

super调用构造器:

  • 在子类的构造器中显式地使用*super (形参列表) *,调用父类中的构造器
  • super(形参列表)的使用,必须声明在子类构造器的首行
  • 因此,this(形参列表)和super(形参列表)只能二选一
  • 在构造器首行,没有显式地声明“this(形参列表)”和“super(形参列表)”,构造器默认调用父类中的空参构造器"super()"
  • 在类的多个构造器中,至少有一个类的构造器使用了“super(形参列表)”,调用了父类中的构造器

5.子类对象实例化过程

  • 从结果看:子类继承父类后,就继承了父类中声明的属性或方法。创建子类的对象,在堆空间中就会加载所有父类中声明的属性。
  • 从过程看:通过子类构造器创建子类对象时,一定会直接或简介地使用父类构造器,以及间接父类的构造器,直到调用java.lang.Object类中的空参构造器。因为加载过所有父类的结构,所以踩在内存中有父类的结构,子类对象才可调用。

6.多态

1.多态性:一个事务的多种形态。

2.对象的多态性:父类的引用指向子类的对象。(只适用于方法、不适用于属性)

3.多态的使用:虚拟方法调用

编译期,只能调用父类中声明的方法;运行期,实际执行的是子类重写父类的方法。

4.多态使用的前提:类之间存在继承关系;方法的重写

 /*有三个类,其中Man、Woman继承Person
 且子类重写父类的方法eat()、walk()
 */
 public class polymorphicStudy {
 ​
     public static void main(String[] args) {
         //2.对象的多态性:
         Person p1 = new Man();
         Person p2 = new Woman();
         
         //3.多态的使用。p1、p2是Person类,但实际执行的是Person子类中重写的方法
         p1.eat();//男人:多吃肉
         p2.walk();//女人:多运动减脂
         
         //4.不能调用Person的子类特有的方法
 //      p1.earnMoney();//挣钱是Man的特有方法
         
         //如何使用子类特有方法:向下转型
         Man t1 = (Man)p2;
     }
 ​
 }
 ​

a instanceof A:判断a对象是否是A的实例。如果是返回true,否则返回false

  • 为了避免在向下转型时出现ClassCastException,可用instanceof先判断
  • a instanceof A的父类,也返回true

7.Object类

java.lang.object类,是所有java类的根父类。如果某个类未extends父类,则其父类为Object

需要知道的几点:

  • Object只构造了空参构造器

  • 没有属性

  • 所有的方法:java8类的官方文档

    • 需要知道clone、equals、finalize(简单了解)、getClass、toString
    • “集合”:hashcode
    • 多线程:notify、notifyAll、wait(3个)

equals()

  1. 只能适用于引用数据类型。

  2. Object.equals()的作用与“==”相同(可以看该方法的源码;思考”==“的含义)

  3. 但是,对于String、Date、File、包装类等重写了equals方法,此时比较的是两个对象的实体内容是否相等。

  4. 自定义类如何重写equals():

    在class内部重写:public boolean equals(Object obj){....} 。此时可以借鉴String等重写的equals思路。

    在开发中:也可以通过eclipse自动生成

toString()

  1. 当我们输出一个对象的引用时,实际上是输出当前对象的toString()。即syso(对象) 和syso(对象.toString())的结果一样,都是地址值。
  2. 于String、Date、File、包装类等也重写了toString()方法。此时再调用,返回的是实体内容
  3. 同样地,toString()也是可以重写和自动生成的。

一个综合练习:

 package com.coderLeo.exer;
 ​
 public class GeometricObject {
     protected String color;
     protected double weight;
     //构造器
     public GeometricObject() {
         super();
         this.color = "white";
         this.weight = 1.0;
     }
     public GeometricObject(String color, double weight) {
         super();
         this.color = color;
         this.weight = weight;
     }
     //getter,setter
     public String getColor() {
         return color;
     }
     public void setColor(String color) {
         this.color = color;
     }
     public double getWeight() {
         return weight;
     }
     public void setWeight(double weight) {
         this.weight = weight;
     }
         
 }
 package com.coderLeo.exer;
 ​
 public class Circle extends GeometricObject {
     private double radius;
     
     //构造器
     public Circle() {
         super();
         this.radius = 1.0;
     }
     public Circle(double radius) {
         super();
         this.radius = radius;
     }
     public Circle(String color, double weight, double radius) {
         super(color, weight);
         this.radius = radius;
     }
     //getter,setter
     public double getRadius() {
         return radius;
     }
     public void setRadius(double radius) {
         this.radius = radius;
     }
     
     public double findArea(){
         return Math.PI * Math.pow(this.getRadius(), 2);
     }
     //重写的equals、toString
     public boolean equals(Object obj){
         if(this == obj)
             return true;
         if(obj instanceof Circle){
             Circle temp = (Circle) obj;//得先向下转型
             return temp.getRadius() == this.getRadius();
         }
         return false;
     }
     //自动生成的
     @Override
     public String toString() {
         return "Circle [radius=" + radius + "]";
     }
 }

测试类:

 package com.coderLeo.exer;
 ​
 public class CircleTest {
 ​
     public static void main(String[] args) {
          Circle test1 = new Circle();
          Circle test2 = new Circle();
          System.out.println(test1.toString());//Circle [radius=1.0]
          System.out.println(test2.toString());//Circle [radius=1.0]
          System.out.println(test1.equals(test2));//true
          
          System.out.println("**************");
          //不相等情况
          Circle test3 = new Circle("black", 10, 2.5);
          Circle test4 = new Circle("green", 7.8, 6.6);
          
          //比较两个Circle的颜色
          System.out.println(test3.getColor().equals(test4));//false,这里其实使用的是String重写的equals方法
          //比较半径是否相等
          System.out.println(test3.equals(test4));//false,这里使用Circle内部重写的equals
          //用重写的toString输出
          System.out.println(test3.toString());//Circle [radius=2.5]
          System.out.println(test4.toString());//Circle [radius=2.5]
          
     }
 ​
 }

8.eclipse单元测试

 package com.coderLeo.test;
 ​
 import org.junit.Test;
 ​
 /*步骤:
  * 1.如果右键工程并点击Build Path没有Add Library,可能是在Java ee视图下,请先切换回去
  * 2.右键点击工程——Build Path——Add Library——JUnity4——下一步即可
  * 3.为了演示操作,创建一个新类专门用于测试。
  *   java类要求:public、有公共的空参构造器
  * 4.声明单元测试方法:
  *   方法要求:public、无形参、无返回值
  * 5.此单元测试方法上需要声明注解:@Test,并在单元测试类导入:import org.junit.Test;
  * 6.如何运行:双击选中方法名——Run As——Junit Test
  *  绿条:无错误;
  *  红条:有错误
  *  
  * 7.如果想要再测试其他的,再来一个@Test并在其下面构造方法即可
  */
 ​
 public class JUnitTest {
     
     int num = 10;
     
     @Test
     public void TestEquals(){
         String s1 = "MM";
         System.out.println(s1.equals("GG"));//fasle
         System.out.println(num);//10
     }
     
     @Test
     public void show(){
         num = 20;
         System.out.println("adbc..");//adbc..
     }
 }

9.包装类(Wrapper)

针对八种基本数据类型定义的相应的引用类型

  • 除了int——Integer、char——Character,其他的类型都是首字母换成大写。
  • 所有的数值型类的父类为Number类

基本数据类型——>包装类:

 public class WrapperTest {
     
     @Test
     public void test1(){
         int num = 20;
         Integer i = new Integer(num);
         System.out.println(i.toString());//Integer的toString也重写过,因此打印其内容20
         
         Person temp = new Person();
         System.out.println(temp.isWoman);//false
         System.out.println(temp.isMan);//null,注意!此时的isMan是Boolean类,某个类未声明时默认值为null
     }
     
 }
 class Person{
     Boolean isMan;
     boolean isWoman;
 }

包装类——>基本数据类型:调用包装类的xxxValue()

 @Test
     public void test2(){
         Float f1 = new Float(15.33);
         System.out.println(f1.floatValue());//15.33
     }

更为方便的,自动装箱和自动拆箱

 @Test
     public void test3(){
         //自动装箱:
         int num1 = 10;
         //直接将int类型赋值给Integer类
         Integer num2 = num1;
         System.out.println(num2);//10
         
         //自动拆箱:
         Integer num3 = new Integer(20);
         //Integer类接收int类型
         int num4 = num3;
         System.out.println(num4);//20
     }

基本数据类型、包装类——>String:调用String重载的xxxvalueOf

 @Test
     public void test4(){
         //基本类型转换String
         int num1 = 123;
         String str1 = String.valueOf(num1);
         System.out.println(str1);//123
         //包装类转换String
         Float f1 = new Float(25.73);
         System.out.println(String.valueOf(f1));//25.73
         
         //或者:用连接运算:“+”
         String str2 = f1 + "";
         System.out.println(str2);//25.73
     }

String——>基本数据类型、包装类:调用包装类的parseXXX(String)

 @Test
     public void test5(){
         String str1 = "12345";
         int num1 = Integer.parseInt(str1);
         System.out.println(num1);//12345,
         //注意此时需要转换的str1必须是个数,如:12345a,则会出现NumberFormatException
         
         String str2 = "TrUe";
         System.out.println(Boolean.parseBoolean(str2));//true   
     }