java入门12--面向对象(上)

本文介绍了Java中的面向过程与面向对象思想。面向过程强调步骤清晰,适合简单问题,而面向对象采用分类思维,适用于复杂问题。面向对象编程的三大特性是封装、继承和多态。文章详细讲解了类与对象的关系,如何创建与初始化对象,以及封装的概念,通过属性私有化和get/set方法实现数据隐藏。此外,还讨论了继承的概念,包括子类继承父类的方法和属性,以及方法重写的原则和应用场景。
摘要由CSDN通过智能技术生成

java入门12

面向过程与面向对象

  • 面向过程思想

    • 步骤清晰,线性思维
    • 适合处理简单问题
  • 面向对象思想

    • 分类思维,对不同类的任务单独思考

    • 适合复杂问题,多人合作

什么是面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)

  • 面向对象编程本质:以类的方式组织代码,以对象的组织封装数据

  • 抽象

  • 三大特性

    • 封装
    • 继承
    • 多态
  • 从代码角度,先有类后有对象,类是对象的模板

类与对象的关系

  • 类是对某一类事物的定义,是抽象的数据类型,对象是抽象概念的具体实例

创建与初始化对象

  • 使用new关键字创建对象
  • 使用new时,除了分配内存空间,还会为创建的对象进行默认初始化以及对类中构造器的调用
  • 类中的构造器也叫构造方法,是创建对象时必须调用的,构造器特点:
    • 必须和类名相同
    • 必须没有返回类型,也不能写void

比如创建一个学生类:

package oop;

//学生类
public class Student {
    //属性
    String name;
    int age;

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

实例化对象:

package oop;

public class Demo01 {
    public static void main(String[] args) {
        //实例化
        //类实例化后会返回一个自己的对象
        //student对象就是一个Student类的具体实例

        Student srrdhy1 = new Student();
        Student srrdhy2 = new Student();

        srrdhy1.name = "艾伦耶格尔";
        srrdhy1.age = 19;

        System.out.println(srrdhy1.name);
        System.out.println(srrdhy1.age);
        srrdhy1.study();
        //艾伦耶格尔
        //19
        //艾伦耶格尔在学习
    }
}

有参构造与无参构造

类:

package oop;

public class Hero {

    //一个类即使什么也不写,也有一个方法
    //显示的定义构造器

    String name;

    //实例化初始值
    //使用new关键字,本质在调用构造器
    //用来初始化值
    public Hero(){
        this.name = "奥克斯";
    }
    //有参构造:一旦定义了有参构造,无参必须显示定义
    public Hero(String name){
        this.name = name;
    }
}

主函数执行:

package oop;

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

        //实例化一个对象
        Hero hero1 = new Hero();
        Hero hero2 = new Hero("黑魔");

        System.out.println(hero1.name);
        System.out.println(hero2.name);
        //奥克斯
        //黑魔
    }
}
//alt + insert用于生成构造器
public Hero(String name) {
        this.name = name;
    }

    public Hero() {
    }

选择Constructor,直接OK生成有参构造,选择Select None生成无参构造。

封装

  • 程序设计追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量方法给外部使用

  • 封装(数据的隐藏)

    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏
  • 属性私有,get/set

创建一个类:

package oop.demo02;

//学生类  private:私有  不能直接在main方法调用了
//这时我们使用public的get和set方法来操作
public class Student {
    //名字
    private String name;
    //学号
    private int id;
    //性别
    private char sex;
    //get获得这个数据
    public String getName(){
        return this.name;
    }
    //set给这个数据设置值
    public void setName(String name){
        this.name = name;
    }

主函数:

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("srrdhy");
        String name1 = s1.getName();
        System.out.println(name1);//srrdhy
    }
}

快捷操作:

    //alt + insert选择Getter and Setter
    //自动生成
    public int getId() {
        return id;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

现在添加一个年龄:

public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

设置一个999岁,但999年龄是不合理的:

s1.setAge(999);
System.out.println(s1.getAge());//非法年龄

规避操作:

    public void setAge(int age) {
        if (age<120 && age>0){
            this.age = age;
        }else {
            System.out.println("输入非法");
        }
    }

封装好处:

  • 提高程序安全性,保护数据
  • 隐藏代码实现细节
  • 统一接口get、set
  • 系统可维护性提高

继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
  • extends意为扩展,子类是父类的扩展
  • java类只有单继承(一个子类不能有多个父类)
  • 除了继承,类与类间的关系还有依赖、组合、聚合
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示
  • 子类与父类间从意义上具有"is a"的关系
  • object类
  • super
  • 方法重写

我们建立一个父类并赋予一个方法:

//人类 父类
public class Person {
    public void speak(){
        System.out.println("说了些什么");
    }
}

建立一个子类继承父类,什么方法也没有写:

//学生 子类
public class Student extends Person{
}

这时在主程序中new一个Student对象,使用speak():

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.speak();
    }
}

可以输出,这表示子类可以调用父类的方法

再比如我们在父类中增加

public int money = 10_0000_0000;

调用:

System.out.println(student1.money);

也可以输出,子类会继承父类的一切

但如果我们把父类的money改为私有的:

private int money = 10_0000_0000;

子类就调用不了了

对于调用权限,由高到低为:

public
protected
default
private

使用快捷键ctrl+H会生成树结构(要把鼠标点在需要的类里)

在这里插入图片描述

可以发现,父类上还有一个类,因为在java中,所有的类默认继承Object类

现在我们在父类建立一个名字,采用protected。

public class Person {

    protected String name = "srrdhy";
}

子类中用private建立一个不同的名字,再写一个输出名字的方法,分别输出三种名字:

public class Student extends Person{

    private String name = "琪亚娜";
    public void printname(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

主程序运行:

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.printname("雷电芽衣");
    }
    //雷电芽衣
    //琪亚娜
    //srrdhy
}

如果我们在父类中写一个print方法:

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

又在子类中写一个同名方法:

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

那么主程序调用print方法时,会调用子类的print

注意,private无法继承,super也不行

现在我们在子类父类各写一个无参构造:

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

主程序中单纯new一个student,什么也不做,会输出:

Person无参执行
Student无参执行

先输出了Person无参执行,说明public Student()里隐藏调用了父类的无参构造,隐藏了一个super()

调用父类的构造器,必须要在子类的第一行

父类没有无参时,子类也不能写无参,只能调用有参。一般我们会把无参写上再接着写有参。

方法重写

  1. 重写都是方法的重写,与属性无关

  2. 子类重写父类的同名方法,参数列表相同

  3. 修饰符:范围可以扩大不能缩小:public>protected>default>private,当然private不能重写

  4. 抛出异常:范围可以缩小不能扩大:ClassNotFoundException–>Exception(大)

子类方法与父类一致,方法体不同

为什么要重写:

  • 父类功能子类不一定需要,或不一定满足

我们建一个子类A,父类B,并写同名方法:

public class A extends B{
    public static void text(){
        System.out.println("A");
    }
}
public class B {
    public static void text(){
        System.out.println("B");
    }
}

调用方法:

public class Main {
    public static void main(String[] args) {
        //方法的调用只和左边,定义的数据类型有关
        A a = new A();
        a.text();//A
        //父类的引用指向了子类
        B b = new A();
        b.text();//B
    }
}

删去A、B的static,发现左边都多了一个东西:

在这里插入图片描述

其实就代表重载

删掉A中方法,alt+insert选择方法重载,直接回车生成方法:
在这里插入图片描述

@Override//注解,有功能的注释
    public void text() {
        super.text();
    }

继续执行主程序,输出BB,把super.text();改回System.out.println(“A”);,继续执行主程序,输出却变成了AA

所以我们可以补全刚刚的结论:

  • 静态方法(有static):方法的调用只和左边,定义的数据类型有关
  • 非静态方法:重写(比如B b = new A();b.text();)

注意重写的方法只能是public,换成private就不行了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值