其他分享
首页 > 其他分享> > 第五章 面向对象

第五章 面向对象

作者:互联网

第五章 面向对象

1 面向对象概念

2 方法的调用

2.1 静态方法与非静态方法

eg.:现有类名Student,该类含有静态方法public static void a(){}和非静态方法public void b(){}

静态方法与非静态方法区别在于:

2.1.1 方法与方法之间的调用

若两个方法都是非静态方法,则可以互相调用

image

若两个方法都是静态方法,则可以互相调用

image

若一个是静态方法,一个是非静态方法,则静态方法不可调用非静态方法,非静态方法可以调用静态方法

image

image

2.2 值传递和引用传递

值传递术后

package com.oop.demo01;

public class Demo02 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);//输出为1

        Demo02.change(a);
        System.out.println(a);//输出为1
    }

    public  static void change(int a){
        a = 10;//无返回值,不会对实参产生影响
    }
}

值传递不会改变变量的值

引用传递

对象是通过引用来操作的:对象是在堆里的

package com.oop.demo01;

public class Demo03 {
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(student.name);//输出为null

        change(student);
        System.out.println(student.name);//输出为Liam
    }

    public static void change(Student student){
        student.name= "Liam";
    }
}

//定义了一个Student类,有一个属性:name
class Student{
    String name;//null
}

引用传递会改变变量的值

3 类与对象的关系

3.1 this关键字

this关键字指代当前类,编写类的时候可以用this打点来调用当前类的属性和方法

3.2 类与类之间的交互调用

eg.:

Student类:

package com.oop.demo02;

public class Student {
    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println(this.name+"在学习");//this代表当前类
    }
}

Application类:

package com.oop.demo02;

public class Application {
    public static void main(String[] args) {
        Student xiaoming = new Student();
        xiaoming.name = "小明";
        xiaoming.age = 23;
        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);

        Student xiaohong = new Student();
        xiaohong.name = "小红";
        xiaohong.age = 22;
        System.out.println(xiaohong.name);
        System.out.println(xiaohong.age);
    }
}

4 ※ 构造器 ※

new一个对象时会跳转到类的默认的无参构造器,这是默认会有的构造器,即使什么构造器都不写在相应的class文件中也会有一个public 类名(){}

Student.java文件如下图:

image

Student.class文件如下图:

image

4.1 构造方法(即构造器)的重载

构造器重载示例

类部分:

package com.oop.demo02;

public class Person {

    String name;
    int age;
    char gender;

    public Person() {
    }

    public Person(String name){
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, char gender) {
        this.name = name;
        this.gender = gender;
    }

    public Person(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

main部分:

package com.oop.demo02;

public class Application {
    public static void main(String[] args) {
        
        Person person1 = new Person();
        Person person2 = new Person("liam");
        Person person3 = new Person("liam",23);
        Person person4 = new Person("liam",'男');
        Person person5 = new Person("liam",23,'男');
    }
}

【注意】即使在java文件中什么都不写,也会默认有一个不显示的无内容的无参构造器,但是一旦定义了有参构造,再想使用无参构造,无参构造就必须显示定义

package com.oop.demo02;

public class Person {

    String name;

    //构造器作用:可以对实例对象的初始默认值进行设定
    //无参构造器:
    public Person(){
        
    }

    //有参构造器:一旦定义了有参构造,再想使用无参构造,无参构造就必须显示定义
    public Person(String name){
        this.name = name;
    }
}

5 对象创建过程中的内存分析

现有Pet类部分:

package com.oop.demo02;

public class Pet {
    String name;
    int age;

    public void shout(){
        System.out.println("叫了一声");
    }
}

main方法部分:

package com.oop.demo02;

public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;
        dog.shout();

        Pet cat = new Pet();
    }
}

内存分析如下图所示:

image

image

6 封装

封装(数据的隐藏)

封装的意义

可以给私有属性一些条件,用以约束属性的范围

6.1 private关键字

eg.现有Student类:

public class Student {

    private String name;
    private int id;
    private char gender;
}

通过private关键字让属性私有化,这使得不能直接用对象名打点来对属性进行赋值操作,与之对应的是public关键字

6.2 私有属性的设置set与获取get

eg.类部分:

package com.oop.demo03;

public class Student {

    private String name;
    private int id;
    private char gender;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age > 120|age < 0){
            System.out.println("ERROR");
        }else {
            this.age = age;
        }
    }//给age属性设置约束,以保证不能随心所欲的设置age的值
}

main部分:

package com.oop;

import com.oop.demo03.Student;

public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setAge(130);
        System.out.println(s1.getAge());
    }
}

最后main部分输出结果:

image

因为age设置了超过设定范围所以输出了ERROR,age没有被成功赋值,还是保持了默认的0

7 继承

子类会继承父类的全部方法和public属性,并不会继承父类的private属性以及private方法

父类部分:

package com.oop.demo05;

public class Person {

    private int money = 10_0000_0000;

    public void talk(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}

子类部分:

package com.oop.demo05;

//Student也是Person
public class Student extends Person{
}

mian部分:

package com.oop;

import com.oop.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.talk();//输出“说了一句话”
        System.out.println(student.getMoney());//输出“1000000000”
    }
}

在创建student对象后可以发现,Student类没有任何方法,但是student对象却能打点调用父类Person里的talk()方法

在Java中,所有的类,都默认直接或者间接的继承Object类

image

快捷键:alt+h可以查看类之间的层次关系:

image

会发现所有类都直接或间接继承Object类

7.1 super关键字

作用

【注意】

7.1.1 用super访问父类的属性

Person父类部分:

package com.oop.demo05;

public class Person{
    protected String name = "liam";
}

Student子类部分:

package com.oop.demo05;

public class Student extends Person{
    private String name = "sprite";

    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

main部分:

package com.oop;

import com.oop.demo05.Person;
import com.oop.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.test("LIAM");
    }
}

输出结果:

image

7.1.2 用super调用父类的方法

Person父类部分:

package com.oop.demo05;

public class Person{

    private String name;

    public Person() {
        System.out.println("我是父类的无参构造");
    }

    public Person(String name) {
        System.out.println("我是父类的有参构造");
        this.name = name;
    }
}


Student子类部分:

package com.oop.demo05;

public class Student extends Person{

    private String name;

    public Student() {
        super();//可以省略
        System.out.println("我是子类的无参构造");
    }

    public Student(String name) {
        //super(name);   //-------(3)
        super();//可以省略
        System.out.println("我是子类的有参构造");
        this.name = name;
    }
}

main部分:

package com.oop;

import com.oop.demo05.Person;
import com.oop.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student1 = new Student();   //-------(1)
        System.out.println("==================");
        Student student2 = new Student("LX");   //-------(2)
    }
}

输出结果:

image

(1)语句执行的是子类的无参数构造方法,内部默认有super(),代表执行父类无参数构造方法,因此输出父类无参数构造方法中的语句和子类无参数构造方法中的语句;

(2)语句执行的是子类有参数构造方法,内部也是默认有super(),代表执行父类无参数构造方法,,输出语句是父类无参数构造方法中的语句和子类有参数构造方法中的语句;

若将(3)语句解除屏蔽,则子类有参构造方法中执行super("LX")表示执行父类有参构造方法Person("LX"),修改后Student子类:

package com.oop.demo05;

public class Student extends Person{

    private String name;

    public Student() {
        super();//可以省略
        System.out.println("我是子类的无参构造");
    }

    public Student(String name) {
        super(name);   //-------(3)
        //super();
        System.out.println("我是子类的有参构造");
        this.name = name;
    }
}

输出结果:

image

对比可得:子类构造器内默认调用父类的无参构造器,只有用super("LX")主动调用父类有参构造才会调用父类有参构造

7.1.3 super()代表子类调用父类的构造方法(在main方法创建一个对象是用new关键字来调用类的构造方法)

Person父类部分:

package com.oop.demo05;

public class Person{

    public Person() {
        System.out.println("Person无参执行了");
    }
}

Student子类部分:

package com.oop.demo05;

public class Student extends Person{

    public Student() {
        super();//隐藏的代码,不写也可以,代表调用了父类的无参构造
        System.out.println("Student无参执行了");
    }
}

main部分:

package com.oop;

import com.oop.demo05.Person;
import com.oop.demo05.Student;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();

    }
}

输出结果:

image

结果表明:在new了student对象时,会先调用父类Person类的构造器,这表示有一个默认的super()被调用了

【注意】

  1. super调用父类的构造方法必须在构造方法的第一行,不然会报错,如图所示

image

  1. super只能出现在子类的方法或者构造方法中
  2. this()表示调用本类的构造方法,super()和this()不能同时调用构造方法,因为this()和super()都要在第一行,如图所示

image

8 方法重写

8.1 重写的作用

在子类中创建一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这

种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。

创建重写方法的快捷键:alt+insert选中override再选中要重写的方法即可

在重写方法时,需要遵循下面的规则:

另外还需要注意以下几条

8.2 重写案例

父类Animal类:

package com.oop.demo05;

public class Animal {

    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void getInfo(){
        System.out.println("宠物名字是"+name+",年龄是"+age);
    }
}

子类Cat类:

package com.oop.demo05;

public class Cat extends Animal{

    private String hobby;

    public Cat(String name, int age, String hobby) {
        super(name, age);
        this.hobby = hobby;
    }

    @Override//注解作用,起到功能注释的作用
    public void getInfo() {
        System.out.println("猫猫的名字是"+name+",年龄是"+age+",爱好是"+hobby);
    }
}

main方法:

package com.oop;

import com.oop.demo05.Animal;
import com.oop.demo05.Cat;

public class Application {
    public static void main(String[] args) {
        Animal animal = new Cat("富贵",3,"吃鱼");
        animal.getInfo();
    }
}

输出结果:

image

9 多态

9.1 多态概念

9.2 多态特点

  1. 多态的前提1:是继承
  2. 多态的前提2:要有方法的重写
  3. 父类引用指向子类对象,如:Animal a = new Cat();//创建一个Cat实例对象a,但a是Animal类型
  4. 多态中,编译看左边,运行看右边

9.3 多态案例

父类Animal类:

package com.oop.demo05;

public class Animal {

    //创建父类普通方法
    public void eat(){
        System.out.println("动物吃啥都行");
    }
}

子类Cat类:

package com.oop.demo05;

public class Cat extends Animal{

    //添加重写方法
    @Override
    public void eat() {
        System.out.println("猫猫爱吃鱼");
    }

    //添加子类特有方法
    public void jump(){
        System.out.println("猫猫跳的老高了");
    }
}

子类Dog类:

package com.oop.demo05;

public class Dog extends Animal{

    //添加重写方法
    @Override
    public void eat() {
        System.out.println("狗狗爱吃肉");
    }

    //添加子类特有方法
    public void run(){
        System.out.println("狗狗跑的老快了");
    }
}

main方法:

  1. 创建”纯纯的“对象用于测试
package com.oop;

import com.oop.demo05.Animal;
import com.oop.demo05.Cat;
import com.oop.demo05.Dog;

public class Application {
    public static void main(String[] args) {
        //1.创建”纯纯的“对象用于测试
        Animal a = new Animal();
        Cat c = new Cat();
        Dog d = new Dog();

        a.eat();//动物吃啥都行,调用的是父类自己的功能
        c.eat();//猫猫爱吃鱼,调用的是子类重写后的功能
        d.eat();//狗狗爱吃肉,调用的是子类重写后的功能
        //a.jump();//报错,Animal类里并没有这个方法
        //a.run();//报错,Animal类里并没有这个方法
        c.jump();//猫猫跳的老高了,子类可以调用自己的功能
        d.run();//狗狗跑的老快了,子类可以调用自己的功能
    }
}
  1. 创建多态对象用于测试
package com.oop;

import com.oop.demo05.Animal;
import com.oop.demo05.Cat;
import com.oop.demo05.Dog;

public class Application {
    public static void main(String[] args) {
        //2.创建多态对象进行测试
        /*口诀1:父类引用指向子类对象
         * 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
        Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存
        Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存
        /*口诀2:编译看左边,运行看右边
         * 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
         *      必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
        a2.eat();//猫猫爱吃鱼,多态对象使用的是父类的定义,子类的方法体
        //a2.jump();//无法调用子类Cat的jump方法
    }
}

9.4 多态的好处

  1. 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
  2. 提高了程序的可扩展性和可维护性

9.5 多态的使用

前提:多态对象把自己看做是父类类型

  1. 成员变量:使用的是父类的
  2. 成员方法:由于存在重写现象,所以使用的是子类的
  3. 静态成员:随着类的加载而加载,谁调用就返回谁的,静态方法属于类资源,不存在重写现象,静态方法在哪个类定义,就作为哪个类的资源使用(final和private也不存在重写现象)

9.6 多态成员使用测试

父类Animal类:

package com.oop.demo05;

public class Animal {
    //创建父类成员变量
    public int sum =10;

    //创建父类普通方法
    public void eat(){
        System.out.println("吃啥都行");
    }

    //定义父类的静态方法play
    public static void play(){
        System.out.println("玩啥都行");
    }
}

子类Dog类:

package com.oop.demo05;

public class Dog extends Animal{
    //创建子类的成员变量
    public int sum = 20;

    //重写父类方法
    @Override
    public void eat() {
        System.out.println("狗狗爱吃肉");
    }

    //创建子类静态方法play
    /*这不是一个重写的方法,只是恰巧在两个类中出现了一模一样的两个静态方法
    静态方法属于类资源,只有一份,不存在重写的现象
    在哪个类定义,就作为哪个类的资源使用
    */
    public static void play(){
        System.out.println("狗狗爱玩球");
    }
}

main方法:

  1. 创建”纯纯的“对象用于测试
package com.oop;

import com.oop.demo05.Animal;
import com.oop.demo05.Dog;

public class Application {
    public static void main(String[] args) {
        //创建”纯纯的“子类对象
        Dog dog = new Dog();
        System.out.println(dog.sum);//20,子类自己的属性
        dog.eat();//狗狗爱吃肉,子类自己的方法
        dog.play();//狗狗爱玩球,并没有重写父类静态方法
    }
}
  1. 创建多态对象用于测试
package com.oop;

import com.oop.demo05.Animal;
import com.oop.demo05.Dog;

public class Application {
    public static void main(String[] args) {
        /*口诀1:父类引用指向子类对象*/
        /*口诀2:编译(保存)看左边,运行(效果)看右边*/
        Animal a = new Dog();
        System.out.println(a.sum);//10,多态中,方法的声明使用的是父类的,方法体使用的是子类的
        a.eat();//狗狗爱吃肉
        /*多态中,调用的静态方法是父类的,因为多态对象把自己看作是父类类型
         * 直接使用父类中的静态资源*/
        a.play();//玩啥都行
        Animal.play();//玩啥都行
    }
}

9.7 instanceof关键字

用途

Java 中的instanceof运算符是用来指出对象是否是特定类的一个实例,返回值是Boolean。

public class Application {
    public static void main(String[] args) {
        Animal a = new Dog();//创建一个Dog实例对象a,但a是Animal类型
        System.out.println(a instanceof Animal);//true,a是Dog实例对象,属于Animal类
        System.out.println(a instanceof Dog);//true,a是Dog实例对象,属于Dog类
        System.out.println(a instanceof Object);//true,a是Dog实例对象,属于Object类
    }
}

9.8 向上转型和向下转型

​ 在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。

那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型。

  1. 向上转型,即低转高:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
  1. 向下转型,即高转低(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象

10 static总结

10.1 static修饰属性

静态变量和实例变量的区别:

10.2 static修饰方法

静态方法跟类一起加载,普通方法跟对象一起加载,与static修饰属性的情况一样。

如Student类有普通方法a()和静态方法b(),a能直接调用b,但b不能直接调用a,要想再b调用a,需要先创建一个Student实例对象,再用对象调用a。

image

10.3 static修饰代码块

package com.oop.demo06;

public class Student {

    //代码块可以赋初始值
    //第二个执行
    {
        System.out.println("匿名代码块");
    }

    //静态代码块只执行一次
    //第一个执行
    static {
        System.out.println("静态代码块");
    }

    //第三个执行
    public Student() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Student student = new Student();
        //输出结果:
        //静态代码块
        //匿名代码块
        //构造方法
    }
}

10.4 通过static静态导入包

package com.oop.demo06;

//静态导入包
import static java.lang.Math.random;

public class Student {

    public static void main(String[] args) {
        System.out.println(random());//静态导入Math.random后可以不用Math.random(),可以省略Math
    }
}

11 抽象类

抽象类是单继承,接口可以多继承(比如插座,约束了可以插什么头,但是没约束可以用什么电器)

父类抽象类:

package com.oop.demo06;

public abstract class Action {

    public abstract void doSomething();//抽象方法,只有方法名字,没有方法的实现

}

子类:

package com.oop.demo06;

//继承了抽象类的子类方法必须要重写父类的方法来实现功能
public class A extends Action{
    @Override
    public void doSomething() {
        System.out.println("do something");
    }
}

抽象的特点

抽象的意义

比如游戏创建新角色,创建新角色的发色、穿着可以重写子类方法即可;可以节省代码,说白了还是为了提高开发效率。

12 接口

12.1 接口的概念

12.2 接口的特点

就像一个类一样,一个接口也能够拥有方法和属性,但是在接口中声明的方法默认是抽象的。(*即只有方法标识符,而没有方法体*)。

eg.

UserService接口:

package com.oop.demo07;

//interface定义的关键字,接口都需要有实现类,实现类名字一般后缀加Impl
public interface UserService {
    //接口中所有定义都是抽象的public

    int AGE = 99;//常量默认有public static final

    void add();//省略了public abstract,默认是有public abstract的
    void delete();
    void update();
    void query();
}

Timer接口:

package com.oop.demo07;

public interface Timer {
    void timer();
}

UserServiceImpl实现类(实现类一般后缀加Impl):

package com.oop.demo07;

//利用imlements关键字实现接口具体功能,实现类可以实现多个接口的功能比如下面还实现了Timer的方法
public class UserServiceImpl implements UserService,Timer{
    //实现类必须要重写接口中的方法,以此实现具体功能
    @Override
    public void add() {
        //具体实现方法
    }

    @Override
    public void delete() {
        //具体实现方法
    }

    @Override
    public void update() {
        //具体实现方法
    }

    @Override
    public void query() {
        //具体实现方法
    }

    @Override
    public void timer() {
        //具体实现方法
    }
}

13 内部类

内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

13.1 内部类的分类

13.2 成员内部类

内部类可以获取外部类的私有属性和私有方法,这是普通类做不到的。

外部类Outer和内部类Inner:

package com.oop.demo08;

public class Outer {

    private int id = 10;

    public void out(){
        System.out.println("这是外部类的方法");
    }

    //内部类Inner
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }

        //内部类可以获取外部类的私有属性
        public void getID(){
            System.out.println(id);
        }

    }

}

//普通类
class method{
    public void getID(){
        //System.out.println(id);//报错,普通类无法获取其他普通类的私有属性
    }
}

调用内部类的方法:

main方法部分:

package com.oop;

import com.oop.demo08.Outer;

public class Application {

    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.in();//输出“这是内部类的方法”
    }

}

13.3 静态内部类

静态内部类无法获取外部类的属性,除非外部类的属性也是静态属性。因为静态成员是随类最先一起加载的。

package com.oop.demo08;

public class Outer {

    private int id = 10;

    public void out(){
        System.out.println("这是外部类的方法");
    }

    public static class Inner{

        public void getID(){
            //System.out.println(id);//报错,静态内部类无法获取外部类的属性,除非外部类的属性也是静态属性
        }

    }

}

13.4 局部内部类

定义在方法中的内部类

package com.oop.demo08;

public class Outer {

    public void method(){

        //局部内部类
        class Inner{
            public void in(){

            }
        }

    }

}

13.5 匿名内部类

package com.oop.demo08;

public class Test {
    public static void main(String[] args) {
        //没有名字的初始化类,不用将实例保存到变量中
        new Apple().eat();
    }
}

class Apple{
    public void eat(){
        System.out.println("吃苹果");
    }
}

标签:子类,面向对象,第五章,oop,Student,父类,com,public
来源: https://www.cnblogs.com/Ayisprite/p/16131455.html