首页 > 编程语言 >JavaSE复习

JavaSE复习

时间:2023-01-05 17:11:48浏览次数:36  
标签:复习 子类 class Person JavaSE 父类 public name

面向对象


  • 面向对象编程(Object - Oriented Programming / OOP)
  • 面向对象编程的本质:以类的方式组织代码,以对象的方式封装数据
  • 三大特性:封装、继承、多态

从认识论角度考虑是先有对象后有类。对象是具体的事物。类是抽象的。

从代码的角度来考虑是现有类再有对象,类是对象的模板。

面向过程 & 面向对象


  • 面像过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么。。。
    • 面向过程适合处理一些较为简单的问题
  • 面向对象思想
    • 以 分类 的思维模式解决问题,先思考解决问题需要哪些分类,然后进行单独思考。最后才对某个分类下的细节进行面向过程的思考。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题

对于描述复杂的事物,从宏观、整体上合理分析,需要用到面向对象的思考方式来分析整个系统,但是具体到细节上,任然需要用到面向过程的思考方式来处理

类与对象


  • 类是一种抽象的东西,是定义某一类东西的东西,但并不代表某一个具体的事物
    • 例如:家具,食物,餐具......
    • 类更像是制造一个对象的图纸
  • 对象是类的具体实例
    • 例如:椅子,炸鸡,筷子......
    • 对象是一个具体的实例,有自己的特点,不是某一个种类,单独的一个个体,不是抽象的

创建与初始化对象


  • 类中的构造器\构造方法,构造器在创建对象时会调用。

    • 类中只有,属性方法
    • 特点一:必须和类的名字相同
    • 特点二:一定,必须没有返回值,但也不能用void。
    public class Student {
    
        // 属性
        String name;    // 未赋值默认为null
        int age;        // 未赋值默认为0
    
        //方法
        public void study(){
            System.out.println(this.name + "正在干饭......");   // this代表当前这个类
        }
    }
    

对象

  • 使用 new关键字创建对象

    • 使用 new关键字创建对象的时候,会给这个对象分配空间
    • 创建好的对象会进行默认初始化,以及对类中构造器的调用
    • 实例化一个对象的过程就像,类是玩具的图纸,通过这个图纸(类)拼出来一个玩具(对象)
    public class Application {
        public static void main(String[] args) {
    
            // 实例化一个之前定义Student类的一个对象
            Student xiaoming = new Student();	// xiaoming这个对象就是一个Student类具体的实例
            xiaoming.name = "小明";	// 给xiaoming的name属性赋值
    
            System.out.println(xiaoming.name);
            System.out.println(xiaoming.age);
        }
    }
    

构造器

什么是构造器?

构造器通常也叫构造方法、构造函数、缺省构造器,构造器在new对象的时候会被调用,可以完成对象的创建同时给变量赋值

使用new关键字,本质是在调用构造器

语法


public 类名 (参数列表,可以没有参数) {
    // 不能有return,返回值为空
}
  • 必须和类的名字相同
  • 一定,必须没有返回值,但也不能用void
  • 当一个类没有构造方法时,系统默认提供无参构造

例:

  1. 创建一个空的Person
public class Person { }	// 里面什么都不定义
  1. 发现能实例化出来这个Person
public class Application {
    public static void main(String[] args) {
        Person person = new Person();
    }
}
  1. 说明 Person类里存在一个空的构造器(无参构造器)
public class Person {
    public Person() {
        // 空的构造器
    }
}
  1. 结论:一个类里面即使什么都不写,也会存在一个方法(无参构造器)

显示的定义一个无参构造器


public class Person {
    public Person() {
        // 无参构造器
    }
}
  • 无参构造器能实例化初始值

    public class Person {
    
        String name;
        
        public Person() {
            // 实例化name的初始值
            this.name = "小明";
        }
    }
    
    public class Application {
        public static void main(String[] args) {
    	// 实例化一个类
            Person person = new Person();
    	// 输出person类的name属性
            System.out.printf("name的值为:" + person.name);
        }
    }
    

    结果:

    name的值为:小明
    

有参构造器


  • 一旦定义有参构造器就一定得显示的定义一个无参构造器
public class Person {

    String name;
    
    // 无参构造
    public Person() { }
    
    // 有参构造
    public Person(String name) {
        this.name = name;
    }
}
  • 在使用Person这个类创建对象时会出现方法重载

    public class Application {
        public static void main(String[] args) {
    	// 实例化对象的时候传入值
            Person person = new Person("小红");
    
            System.out.printf("值为:" + person.name);
        }
    }
    

    结果:w

    name的值为:小红
    

    因为使用这个类时有值传入,所以程序就往有参构造那走了

封装


在面向对象程式设计方法中,封装(Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。

也就是隐藏内部的实现细节,外部不能查看,通过提供对外的方法来调用与修改。

封装能让代码更易于理解与维护,同时也增强了代码的安全性。

  • 封装(数据的隐藏)
    • 程序设计追求 “高内聚,低耦合
    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
    • 低耦合:仅暴露少量的方法给外部使用
  • 简单来说就两个东西: getset
  • 所有实例相关的东西都是用引用.来访问
  • 所有静态相关的东西都是用类名.来访问

实现封装


  • 通过 private 关键字设置为私有属性,再设置公共的 getset 方法方便外部取得、设置name的值。
public class Student {

    // 私有的名字变量
    private String name;

    // 取得名字的值
    public String getName() {
        return this.name;
    }

    // 设置名字的值
    public void setName(String name) {
        this.name = name;
    }
}
  • 封装还可以进行判断输入值是否合法,或者更多骚操作。

  • 实例:

    public class Student {
    
        // 私有的名字变量
        private String name;
    
        // 私有的性别变量
        private char sex;
    
        // 取得名字的值
        public String getName() {
            return this.name;
        }
    
        // 设置名字的值
        public void setName(String name) {
            this.name = name;
        }
    
        // 取得sex
        public char getSex() {
            return sex;
        }
    
        // 设置sex过程中加入判断,防止输入不合法的值
        public void setSex(char sex) {
            if (sex == '男' || sex == '女') {
                this.sex = sex;
            }else {
                System.out.println("输入不合法!");
            }
        }
    }
    

    调用:

    import com.wnaoii.oop.Demo03.Student;
    
    public class Application {
    
        public static void main(String[] args) {
            Student student = new Student();
    
            student.setName("小明");
            System.out.println("名字叫:" + student.getName());
            System.out.println("--------------");
    
            // 输入值不合法
            student.setSex('爬');
            System.out.println(student.getSex());
    
            // 输入值合法
            student.setSex('男');
            System.out.println("性别为:" + student.getSex());
        }
    }
    

    结果:

    名字叫:小明
    --------------
    输入不合法!
     
    性别为:男
    

继承


  • B类继承A类,则A类是B类的超类(superclass)、父类、基类,B类是A类的子类(subclass)、派生类、扩展类
  • 子类继承父类,且拥有父类的实例域和方法,但构造方法不继承,私有属性不能在子类中直接访问(通过super.关键字来访问)
  • 继承能增加代码的重复利用率
  • Java中只有单继承,没有多继承(一个孩子一个爹)
  • 所有类都继承至一个Object类,它是所有类的祖宗
  • 继承的缺点:耦合度高,父类一旦修改,所有的子类全都受到牵连

image

类的继承格式


Java中通过 extends 关键字声明

class 父类 {
}

class 子类 extends 父类 {
}
  • Objext类是个特殊类,我称之为祖宗类,所有类都默认继承 Object类。
  • 子类具有父类所有字段,之后定义不能和父类重复。

super & this


  • super关键字:

    • 代表父类,子类调用父类的字段时,用super.fileldName调用。

    • 只能在有继承的情况下才能使用

    • 构造方法:this( ); 本类的构造器

  • this关键字:

    • 代表自己,指向自己的引用,用 this.fileldName调用。
    • 没有继承也可以使用
    • 构造方法:super( );父类的构造器

实例:

  • 定义一个 Person
package com.wnaoii.oop.Demo04;

public class Person {
    protected String Name = "父类Name";
    private int Age = 13
}
  • 再定义一个 Student 类继承 Person
package com.wnaoii.oop.Demo04;

// 子类
public class Student extends Person {

   private String Name = "子类Name";

   public void printName(String name) {
       System.out.println(name);	// 这个 name 调的是形式参数 name
       System.out.println(this.Name);	// this.name 调的是当前这个类的 Name 
       System.out.println(super.Name);	// super.name 调的是当前这个类父类的 Name
   }
}
  • 实例化 student 对象查看效果
package com.wnaoii.oop.Demo04;

public class Application {
    public static void main(String[] args) {

        Student student = new Student();

        student.printName("参数name");

    }
}

结果:

参数name
子类Name
父类Name

super 注意点

  • super 调用父类构造方法,必须在构造方法的第一个。
  • super 必须只能出现在子类的方法或构造方法中。
  • super 和 this 不能同时调用构造方法。(因为两者都必须在第一行,有冲突)

protected

  • 在继承中,子类无法访问父类的private字段或者private方法。
  • protected关键字可以把字段和方法的访问权限控制在继承树内部,一个protected字段和方法可以被其子类,以及子类的子类所访问。

无法调用:

// 父类
public class Person {
    // 定义一个 private name变量
    private String name = "父类Name";
}
// 子类
public class Student extends Person {
    public void printName() {
        System.out.println(super.name);	// 编译错误,无法调用
    }
}

成功调用:

  • 由于 private 关键字使得子类无法调用,则可以把 private 改为 protected,这样子类便能调用父类被 protected 修饰的字段。
// 父类
public class Person {
    // 定义一个 protected name变量
    protected String name = "父类Name";
}
// 子类
public class Student extends Person {
    public void printName() {
        System.out.println(super.name);	// 子类通过关键字 super 成功调用
    }
}

继承中的构造器


  • 子类并不继承父类的构造器(构造方法或者构造函数),只是调用(隐式或显式)。
// 父类
public class Person {
    // 一个简单的无参构造
    public Person() {
        System.out.println("已执行Person无参构造!")
    }
}
// 子类
public class Student extends Person {
    
    // 此处隐藏了一个调用父类的无参构造
    // super();
    
    public Student() {
        System.out.println("已执行Student无参构造!")
    }
}
// 调用
public class Application {
    public static void main(String[] args) {
		// 只用 Student 类创建一个对象
        Student student = new Student();
    }
}

结果:

已执行Person无参构造!
已执行Student无参构造!

显示调用父类无参构造则必须在子类构造器的第一行。(不写一般都默认调用父类无参构造器)

若父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。

若父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。

方法重写(override)


为什么要重写?

  • 父类的功能,子类不一定需要,或子类需要的更多!

特点:

  • 子类和父类需要有继承关系
  • 重写是对父类可访问的方法的重写,和属性无关
  • 声明为 final 的方法不能被重写
  • 声明为 static 的方法不能被重写,但是能够被再次声明
  • 修饰符的范围可以扩大但不能缩小。(public > protected > Default > private)
  • 抛出的异常范围可以被缩小,但不能扩大
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类。(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)
  • 方法名、返回值、形参必须相同,方法体不同。(外壳不变,核心重写

例:

package com.wnaoii.oop.Demo05;

public class Person {
    public void say() {
        System.out.println("Person会说话!");
    }
}
package com.wnaoii.oop.Demo05;

public class A extends Person {
    @Override
    public void say() {
        System.out.println("A不但会说,还会唱、跳、Rep!");
    }
}
package com.wnaoii.oop;

import com.wnaoii.oop.Demo05.Person;
import com.wnaoii.oop.Demo05.A;

public class Application {
    public static void main(String[] args) {

        Person person = new Person();
        person.say();

        A a = new A();
        a.say();
    }
}

输出:

Person会说话!
A不但会说,还会唱、跳、Rep!

多态


一个类的多种形态

父类型引用指向子类型对象

编译时一种形态,运行时一种形态,这就是多态

编译时多态:通过 overloading(重载) 实现

编译阶段绑定父类型的方法

运行时多态:通过 overriding(重写) 和 继承实现

运行阶段动态绑定子类型对象的方法

多态存在的三个条件


  • 拥有继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象:Parent p = new Child( );
    • upcasting 向上转型(父-->子 自动类型转换):将子类对象直接赋值给父类引用
    • 只有向上转型过的对象才能向下转型
    • downcasting 向下转型(子-->父 强制类型转换):将指向子类对象的父类引用赋值给子类引用

QQ图片20221220144338

实例:

package com.wnaoii.oop.Demo06;

//父类
public class Person {

    public int age = 0;

    public void run() {
        System.out.println("run");
    }
}

和父类有继承关系的Student类:

package com.wnaoii.oop.Demo06;

// 子类
public class Student extends Person {

    public int age = 19;

    // 重写父类的 run() 方法
    @Override
    public void run() {
        System.out.println("子类run()方法被调用!");
    }
    // 子类特有的方法
    public void eat() {
        System.out.println("子类特有eat()方法被调用!");
    }
}

调用:

package com.wnaoii.oop;

import com.wnaoii.oop.Demo06.Person;
import com.wnaoii.oop.Demo06.Student;

public class Application {

    public static void main(String[] args) {

        Student s1 = new Student();
        // 父类的引用指向子类的对象(向上转型)
        Person s2 = new Student();

        // 多态成员方法调用
        s1.run();   // 能调用自己的和继承的方法
        s1.eat();	// 类型是 Student 正常调用
        System.out.println();

        s2.run();   // 子类重写了父类的方法,所以优先执行子类的方法
        // s2.eat();	s2的类型为 Person ,而Person中没有eat()方法,无法调用
        System.out.println();

        // 多态成员变量调用
        System.out.println(s1.age);
        System.out.println(s2.age);

    }
}

结果:

子类run()方法被调用!
子类特有eat()方法被调用!

子类run()方法被调用!

19
0

由此可以看出多态成员访问的特点:

成员变量:编译看父类(左边),运行看父类(左边)

在程序的编译阶段,根据父类中的变量进行编译,实际运行时也是根据父类的变量进行运行

成员方法:编译看父类(左边),运行看子类(右边)

在程序的编译阶段,根据父类的方法进行编译,父类有这个方法编译通过,没有则报 ClassCastException异常(类型转换异常),在实际运行时则运行的是子类中的方法

具体分析

例:有一个Animal的父类,有一个move()方法,一个Dog子类,重写了父类的move方法

Animal dog = new Dog();

编译阶段:

对于编译器来说,编译器只知道dog这个对象的类型是Animal,所以编译器在检查语法的时候只会去Animal.class字节码文件中找父类的move()方法,找到了就绑定上move()方法,编译通过,静态绑定成功!(编译阶段属于静态绑定)

运行阶段:

在运行阶段中,实际上堆内存中创建的java对象是Dog的对象,所以运行move()方法时,实际参与的是一只dog,是对Dog对象中重写的move()方法的调用。(运行阶段绑定属于动态绑定)

向上转型


向上转型(Upcasting)是指将子类的引用赋值给父类的变量的过程,又或者说是将一个对象的类型转换为它的父类型或接口类型。这个过程也称为向上转型。这种转型是自动的,并且在大多数情况下都是安全的。

特点:

  • 向上转型是安全的:由于父类包含了子类的所有方法和属性,所以向上转型后对象仍然可以使用所有的方法和属性
  • 向上转型会丢失子类特有的方法和属性:由于向上转型后的对象只能访问父类的方法和属性,所以子类特有的方法和属性将不再可用
  • 向上转型可以使用 instanceof 运算符进行检测:可以使用 instanceof 运算符来检测对象是否是特定类型的实例。这对于在向上转型后确定对象的类型很有用
  • 向上转型可以使用强制类型转换进行恢复:如果需要访问子类特有的方法和属性,则可以使用强制类型转换将对象转回原来的子类类型。但是,这需要进行类型检查,以确保转换是安全的

例:假设有一个类型为Dog的对象,它有一个父类型为Animal。在这种情况下,可以将Dog对象向上转型为Animal类型,如下所示:

Animal animal = new Dog();

在这种情况下,animal变量仍然指向原来的Dog对象,但是可以通过animal变量调用的方法受到限制。例如,如果Dog类中有一个名为run的方法,则无法通过animal变量调用这个方法,因为Animal类中没有这个方法,这个方法是子类Dog特有的方法。

向下转型

向下转型(downcasting)是指将一个对象的引用从父类型向子类型转型。因为它可以让我们在不改变对象本身的情况下改变对对象的引用。这种转型不是自动的,且不安全!

特点:

  • 只有向上转型过的对象才可以向下转型
  • 向下转型是不安全的:由于向下转型后的对象会访问子类特有的方法和属性,所以如果对象本身不是子类的实例,就会发生类型转换异常
  • 向下转型可以使用 instanceof 运算符进行检测:可以使用 instanceof 运算符来检测对象是否是特定类型的实例。这对于在向下转型前确定对象的类型很有用
  • 向下转型必须使用强制类型转换:必须使用强制类型转换将对象转换为子类类型。但是,这需要进行类型检查,以确保转换是安全的

例:假设有一个类Animal和它的子类Dog,并且有一个Animal类型的对象animal,我们可以将animal向下转型为Dog类型,如下所示:

Animal animal = new Animal();
Dog dog = (Dog)animal

但是,如果animal对象本身不是Dog类的实例,animal是其他类new实例化出来的对象,在这种情况下,尝试向下转型将会导致类型转换异常ClassCastException。如下所示:

Animal animal = new cat();
Dog dog = (Dog)animal;

因此,在进行向下转型之前,通常会使用instanceof运算符来检测对象是否是特定类型的实例,以确保转换是安全的。

instanceof运算符的使用


可以在运行阶段动态判断引用指向的对象的类型,instanceof运算符的运算结果只能是布尔类型

规范:任何时候,任何地点,对类型进行向下转型时,一定要使用instanceof运算符进行判断

语法

引用 instanceof 类型

例1: a 是一个引用, a 变量保存了内存地址指向了堆中的对象

  • a instanceof Animal运算结果为true

    a引用指向的堆内存中的java对象一个Animal

  • a instanceof Animal运算结果为true

  • a引用指向的堆内存中的java对象不是一个Animal

例2:父类Animal,子类1Cat,子类2Dog

Animal a = new cat();
// 将Animal类型的a引用向下转型,Dog类和Cat类都继承自Animal类,但Dog类和Cat类相互并没有继承关系,此时强转就会出现类型转换异常
Dog dog = (Dog)a;

使用instanceof运算符进行判断

// 向上转型
Animal a = new cat();
// 添加instanceof运算符判断
if (a instanceof Dog) {
    // 运算结果为true时才开始向下转型
    Dog dog = (Dog)a;
}

什么时候需要使用向下转型?


父类需要访问子类中特有的方法时需要向下转型

多态在开发中的实际应用


多态在开发中的作用:降低程序的耦合度,提高程序的扩展力

编写一个程序模拟主人喂养宠物的场景:

提示1:

  • 主人类:Master
  • 宠物类:Pet
  • 宠物类子类:Dog、Cat、fish

提示2:

  • 主人应该提供一个喂养的方法:feed()
  • 宠物应该有一个吃的方法:eat()

要求:主人类中只提供一个feet()方法,达到喂养各种类型宠物的目的

编写测试程序:

  • 创建主人对象
  • 创建各种宠物对象
  • 调用主人的feed()方法喂养不同的宠物,观察执行结果

编写过程:

  1. 创建主人类

    public class Master {}
    
  2. 创建宠物类,实现eat()方法

    public class Pet {
        public void eat() {}
    }
    
  3. 创建宠物类子类,重写父类的eat()方法

    1. Dog类

      public class Dog extends Pet{
          public void eat() {
              System.out.println("小狗正在吃骨头!");
          }
      }
      
    2. Cat类

      public class Cat extends Pet{
          public void eat() {
              System.out.println("小猫正在吃鱼!");
          }
      }
      
    3. Fish类

      public class Fish extends Pet{
          public void eat() {
              System.out.println("小鱼正在吃小虾米!");
          }
      }
      
  4. 在主人类中添加feed()方法实现喂养多种类型的宠物

    public class Master {
        // 形参使用各种宠物的父类pet,传参时自动向上转型
        public void feed(Pet p){
            p.eat();
        }
    }
    
  5. 编写测试类开始测试

    public class Test {
        public static void main(String[] args) {
            // 创建主人对象
            Master master = new Master();
            // 创建各种宠物对象
            Dog dog = new Dog();
            Cat cat = new Cat();
            Fish fish = new Fish();
            // 调用主人的feed()方法喂养不同的宠物
            master.feed(dog);
            master.feed(cat);
            master.feed(fish);
        }
    }
    
  6. 输出结果

    小狗正在吃骨头!
    小猫正在吃鱼!
    小鱼正在吃小虾米!
    

标签:复习,子类,class,Person,JavaSE,父类,public,name
From: https://www.cnblogs.com/WNAOII/p/17028161.html

相关文章

  • Java 复习篇2---jdk
    jdk文件:bin该路径下存放了各种工具命令,其中重要的有javac和Javaconf:改路径下存放了相关配置文件include:该路径下存放了一些平台特定的头文件jmods;该路径下存放......
  • Java复习篇3---基础概念
    关键字关键字:被Java赋予了特定含义的英文单词关键字的字母全是小写常用的代码编辑器,针对关键字会有特殊的颜色标记,非常直观例如:class:用于(创建\定义)一个类,后面紧......
  • 框架课学习笔记--复习篇
    现在springboot框架课完成前端游戏界面,后端登录注册页面。现在复习vue,巩固学到的知识,反复的看git的两个作用,一可以看到历史版本代码。存档的功能。二同步代码同步不......
  • 1.2复习了一下MySQL的索引
    今天又复习了一下索引,做一个总结吧主要就是复习了索引分类概念,索引使用,SQL优化等三个方面1.主键索引,唯一索引,常规索引;对于唯一索引,同一个表中可以创建多个,用作创建唯一......
  • (数学分析复习)含参量积分总结
    文章目录写在前面总结一下含参量正常积分、含参量反常积分、Euler积分,这部分内容主要为曲线积分曲面积分以及多重积分做铺垫。主要参考《数学分析(第四版)下册》(华东师范大......
  • Java编程技术期末复习总结
    Java编程技术期末复习总结一、Java编程基础下列软件包中,不需要使用import指令就可直接使用的是____。A.java.langB.java.textC.java.sqlD.java.utilA在java......
  • 一文带你复习好Mysql的核心知识点
    SQL优化调优是体现程序员分析归纳能力的有效手段,虽然我们不是DBA,但是编码开发时也会涉及许多对数据库的CRUD需求。因此,通过理解Mysql数据库的底层原理,对我们的笔试面试,还有......
  • 数据挖掘原理与应用期末考试复习
    1绪论数据挖掘定义数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的数据中提取隐含在其中的、人们事先不知道的、但又是潜在有用的信息和知识的过程。数据挖掘......
  • 复习Stream流,函数式接口,方法引用
    今天对这些内容进行了一个复习,以写demo加做笔记的形式stream能够更加优雅的处理集合、数组等数据,让我们写出更加直观、可读性更高的数据处理代码创建steam流的方式set、......
  • html css js复习
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content=......