java特性:封装、继承、多态

目录

一、封装

1、为什么需要封装

2、方法重载

3、构造器

二、继承

1、类之间的关系:

2、super关键字

3、方法重写override

 三、多态

1、使用多态的好处


一、封装

1、为什么需要封装

        面向对象编程语言,需要对现实世界中的事物进行抽象、模拟。现实世界中的对象属性,都是隐藏在对象内部的,外界无法直接操作和修改。

        在类中定义属性的时候,一般需要把属性隐藏起来。 如果外界需要访问这个属性,那么就提供公共方法对其访问。

例如:

public class Student{
//使用private关键字来修饰属性,不允许外部直接访问该属性
    private String name;
    //提供公共的setName方法,可以让外部调用该方法给name属性赋值
    public void setName(String name){
        this.name = name;
    }
    //提供公共的getName方法,可以让外部调用该方法获取name属性的值
    public String getName(){
        return name;
    }
}

代码中, private 修饰符的特点:

  • private是四种权限修饰符中的一种,并且是权限最小的一种
  • private可以修饰成员变量和成员方法
  • private修饰属性和方法,就只在当前类中才能访问,在当前类以外的其他地方,都不能访问
  • private修饰的属性,称为类中的私有属性,
  • private修饰的方法,称为类中的私有方法

 例如:

public class Student{
    //私有属性,只允许在当前类中访问,出了这个类的范围,就不能访问
    private String name;
    //私有方法,只允许在当前类中调用,出了这个类的范围,就不能调用
    private void test(){
    }
}
public class Test{
    public static void main(String[] args){
    Student stu = new Student();
    stu.name = "tom";//编译报错,不允许访问
    stu.test();//编译报错,不允许访问
    }
}

封装的优点

  1. 提高代码的安全性,重要信息可以私有化,不对外暴露
  2.  提高代码的复用性,常用的代码或者功能封装到方法中,可以在其他地方反复调用
  3.  封装代码的实现细节,便于修改内部代码,提高可维护性
  4.  简化外部的调用,便于调用者使用

 其实,我们在定义一个类的时候,就是在完成封装的过程。

2、方法重载

        什么是方法重载?

        类中有多个方法,具有相同的方法名,但是方法的参数各不相同,这种情况被称为方法的重载 (overload)。

        System.out.println 中的 println 方法,可以处理很多中参数的情况,例如,可以处理无参的,int 类型参数的,String类型参数的,double类型参数的、boolean类型参数的、char类型参数的等 其实 println 并不是一个方法,而是有很多个 println 方法,这些方法分别可以处理不同的情况,因 为它们的参数列表是不一样的。

        如图: 

               

 方法的重载,必须是在同一个类中,并且要求如下:

1、方法名必须相同

2、参数列表必须不同

  • 参数列表里参数个数不同
  • 参数列表类型不同
  • 参数列表参数顺序不同 

3、方法的修饰符、返回类型、抛出异常这些地方没有限制(可以相同,也可以不同,但一般都是相 同的) 

3、构造器

构造器有以下两个特点:

  • 必须和类的名字保持一致
  • 必须没有返回类型,也不能写void

 构造器的作用:

  • 使用new关键字来创建对象的时候,后面跟的必须是类中存在的构造器
  • 构造器中的代码,在对象创建后会被调用,从而可以完成对象的初始化工作
public class Student{
    private String name;
    private int age;
    //构造器
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args){
        //创建对象的时候使用构造器
        //并且传参到构造器中,构造器中可以使用这些参数给属性进行初始化
        Student stu = new Student("tom",20);
    }
}

         构造器的重载:除了默认的无参构造器之外,在类中还可以对构造器进行重载,让构造器可以接收一些参数,然后使用 这些参数进行对象的初始化工作。

public class Student{
    private String name;
    private int age;
    //无参构造器
    public Student(){}
    //有参数构造器,接收参数,进行对象属性的初始化
    public Student(String name){
        this.name = name;
    }
    public Student(int age){
        this.age = age;
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
}

构造器之间的调用: 使用this关键字,可以在构造器中,调用另一个构造器

public class Student{
    private String name;
    private int age;
    //无参构造器
    public Student(){
    //调用俩参的构造器
        this("tom",20);
    }
    public Student(String name){
    //调用俩参的构造器
        this(name,0)
    }
    public Student(int age){
    //调用俩参的构造器
        this(null,age);
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
}

 默认构造器: 即使在类中没有定义构造器,那么在编译之后,也会自动的生成一个无参构造器,并且构造器中不执行 任何代码。这个无参构造器就被称为默认的构造器。 我们也可以主动在类中定义出这个无参的默认构造器:

         !!!需要注意的是,如果我们在类中定义了一个构造器,那么系统就不在为该类生成无参的默认构造器 了。

二、继承

1、类之间的关系

        类和类之间的关系有很多种,继承就是其中一种关系,除此之外还有依赖组合聚合等。

继承的例子:

        继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。  

        子类继承父类,子类就可以继承父类中定义的属性和方法。父类更通用,子类更具体

 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么这些类(子类)就不需要 再定义这些属性和行为,只要继承同一个类(父类),它们就可以直接访问父类中的非私有的属性和方法。

继承的好处:

  •  提高代码的复用性。
  • 类与类之间产生了关系(is a),这是使用多态特性的前提。

 继承的关键字: 子类继承父类,使用关键字  extends

    //定义Person类,作为父类
public class Person{
    String name;
    public void sayHello(){
        System.out.println("hello~ I am "+name); 
    }
}
    //定义Student类,作为子类
class Student extends Person{
    public static void main(String[] args){
        Student stu = new Student();
    stu.name = "tom";//name属性从父类中继承而来
    stu.sayHello();//sayHello方法从父类中继承而来
    }
}

         从语法上讲,一个类可以继承任何的另一个类,只要满足语法要求即可。但是从意义上来考虑的 话,这种继承关系可能并不合适。一般只有具有"is a"关系的俩个类直接,才会考虑是否要使用继承。Object类是其他类的根类。

子类继承父类,继承了父类中的属性和方法,并可以在子类中访问这些属性和方法:

//定义Person类,作为父类
public class Person{
    String name;
    private int age;
    public void sayHello(){
        System.out.println("hello~ I am "+name);
    }
}
//定义Student类,作为子类
class Student extends Person{
//这个是子类中单独定义的方法,和父类无关
    public void hi(){
        name = "jack";//访问从父类中继承过来的方法
        sayHello();//调用从父类中继承过来的方法
        age = 20;//编译报错,age是父类中的私有属性,子类中不能访问
    }
}

 父类中的私有属性和方法,子类中不能访问。

注意,父类中的构造器,子类是不能继承的。

 java中,类和类之间的继承是单继承;如果没有给类指定父类的话,那么这个类会默认继承父类Object。

Object类中的方法 :

绿色圆点表示public修饰方法,黄色菱形表示protected修饰的方法,红色方块表示private修饰的方式

注意,Object类中没有属性。

java中,每个类都是直接或者间接了继承了Object,可以说Object是所有类的父类类型

 子类继承父类,创建子类对象的时候,会先默认调用父类的构造器:

//定义Person类,作为父类
public class Person{
    public Person(){
        System.out.println("Person类中的构造器被调用");
    }
}
//定义Student类,作为子类
class Student extends Person{
    public Student(){
        System.out.println("Student类中的构造器被调用");
    }
}
    public static void main(String[] args){
        new Student();
    }

 //main方法执行会输出以下语句:
Person类中的构造器被调用
Student类中的构造器被调用

         子类继承父类,会继承父类的属性和方法,那么就需要先调用父类的构造器对父类中的属性进行初始化,初始化完成后再给子类使用。 构造器的作用之一就是进行初始化

2、super关键字

 在子类中,使用super关键字一般做以下事情:

  • 访问父类中的属性
  • 调用父类中的方法
  • 调用父类中的构造器

        在构造器中,可以使用this调用类中其他构造器,也可以使用super调用父类中的构造器。 但是thissuper这俩种调用构造器的代码,不能同时出现,否则会报错

        这是因为this调用构造器的语句和super调用构造器的语句,都要求自己是第一句代码,但是构造器中的 第一句代码只能有一个,所以它们俩个不能同时出现,例如:

public class Person{
    public Person(){
    }
}
public class Student extends Person{
//编译报错,在使用this和super调用构造器功能的时候,它们俩个不能同时出现
    public Student(){
        this("tom");
        super();
    }
    public Student(String name){
    }
}

但是,如果this和super不是都要调用构造器,那么同时出现就没有问题,例如:

public class Person{
    public void sayHello(){
    }
}
public class Student extends Person{
    //编译通过
    public Student(){
        this("tom");
        super.sayHello();
    }
    public Student(String name){
    }
}

3、方法重写override

什么是方法重写?

如果子类和父类中出现了相同的方法,这种情况就叫做方法重写 (Override)。 注意,方法重载是发生在同一个类中,方法重写发生在子父类之间

 父类中的一个方法和子类中的一个方法,满足以下要求,就是方法的重写

  • 方法名必须相同
  • 参数列表必须相同
  • 访问控制修饰符可以被扩大,但是不能被缩小,例如父类protected,子类可以是public,但不能是private;public > protected > default > private
  • 方法抛出异常类型的范围可以被缩小,但是不能被扩大 。

        例如:ClassNotFoundException --扩大--> Exception

  • 返回类型可以相同,也可以不同

        如果父类的返回类型是引用类型,子类重写后的方法返回类型可以和父类方法的返回类型保持 一致,也可以是父类方法返回类型的子类型 例如,父类方法的返回类型是Person,子类重写后的返回类可以是Person也可以是Person的子 类型

        如果父类的返回类型是基本类型,那么子类重写后的返回类型必须和父类的保持一致 例如: 父类方法的返回类型是int,子类重写后的返回类也必须是int

(个人认为记忆时可以记成必须相同,因为基本类型子类返回值必须相同,引用类型是他的子类,也是is-a的关系,相当于也是这个引用类型)

注意,大多数情况下,子类中重写的方法会和父类中的方法完全保持一致,只有方法的实现不 同。(也就是大括号中代码不一样)

 父类中哪些方法不能被重写:

  • 父类中的静态方法不能被重写
  • 父类中私有方法不能被重写

 只有在子类中,可以直接访问到的,父类的方法,并且是非静态的方法,才能被子类重写

 常见的重写情况,例如:

public class Person{
    public void sayHello(){
        System.out.println("你好!很高兴认识你");
    }
}
public class Student extends Person{
    //子类中,重写父类的sayHello方法
    public void sayHello(){
        System.out.println("hello!nice to meet you");
    }
}
    public static void main(String[] args) {
        Student stu = new Student();
        //由于子类重写了sayHello方法,所以这里将会调用到子类中重写后的sayHello
        //如果子类中没有重写sayHello方法,那么这里将会调用到从父类继承过来的sayHello方法
        stu.sayHello();
}

子类继承父类,在调用方法的时候,如果子类中没用重写,那么调用的是从父类继承的方法,如果 子类重写了这个方法,那么将会调用到子类中重写后的方法。非常重要

 三、多态

        相同类型的不同对象,调用同一个方法,最终执行结果是不同的。

        例如,猫、狗、猎豹都属于动物类,它们都有“跑”这个共同的行为,但是它们各自跑起来的方式又是不 一样的。由此可见,不同的对象,进行同一个行为,但是它们的表现出来的确实不同的形态。 java中的多态,就是来描述这种情况的。

多态的前提

  • 子类继承父类
  • 子类重写父类中的方法
  • 父类的引用指向子类对象

 注意,类实现接口,这是一种特殊形式的继承,多态也可以体现在类和接口的关系中。

 

public class Person {
    public void sayHello(){
        System.out.println("你好!");
    }
}
class Student extends Person{
    public void sayHello(){
        System.out.println("hello!我是一名酷酷的学生");
    }
}
class Teacher extends Person{
    public void sayHello(){
        System.out.println("hi!我是一名酷酷的老师");
    }
}
    public static void main(String[] args) {
    //声明父类的引用
        Person person;
        int random = (int) (Math.random()*10);
    //根据随机数的情况,让父类引用person指向不同的子类对象(Student对象或者Teacher对象)
        if(random%2 == 0){
            person = new Student();
        }
        else{
            person = new Teacher();
        }
    //使用person引用,调用子类对象中重写的方法
    //关键点在于,在调用sayHello方法的时候,引用person指向的对象是谁
    person.sayHello();
}

同一类型(Person)的引用,指向不同的子类对象(Student或者Teacher),调用同一个方法 (sayHello),最后是不一样的表现形式(执行结果不同)!

使用多态的好处:

第一种情况,不使用多态:

public class Game {
    public void start(BasketBall basketBall){
        basketBall.play();
    }
    public void start(Football football){
        football.play();
    }
}
class BasketBall{
    public void play(){
        System.out.println("篮球游戏开始初始化...");
    }
}
class Football{
    public void play(){
        System.out.println("足球游戏开始初始化...");
    }
}
    public static void main(String[] args) {
        Game game = new Game();
        BasketBall basketBall = new BasketBall();
        game.start(basketBall);
        Football football = new Football();
    game.start(football);
    }
}

 在这种情况下, 如果多了一种乒乓球游戏要运行,代码代码要如果修改?

 如果一直不断的新增游戏的种类,代码修改的起来是否会很麻烦?

 使用多态

public class Game {
//这里只需要定义一个方法,参数类型是Ball类型
//这个Ball是父类,它的引用可以指向任何一个子类对象
    public void start(Ball ball){
        ball.play();
    }
}
//父类
class Ball{
    public void play(){}
}
//子类
class BasketBall extends Ball{
    public void play(){
        System.out.println("篮球游戏开始初始化...");
    }
}
//子类
class Football extends Ball{
    public void play(){
        System.out.println("足球游戏开始初始化...");
    }
}
/*整个代码中,基本只有这里是新增的,其他地方不需要改动*/
/*新增乒乓球类*/
class PingPangBall extends Ball{
    public void play(){
        System.out.println("乒乓球游戏开始初始化...");
    }
}
    public static void main(String[] args) {
        Game game = new Game();
        //声明父类的引用
        Ball ball;
        //指向一个子类对象
        ball = new BasketBall();
        //这里想要切换游戏,只需要让引用ball执行对应的子类对象即可
        //ball = new FootBall();
        //ball = new PingPangBall();
        game.start(ball);
    }
}

可以看出,这时候想新增一个球类游戏,并且去运行它,几乎不需要修改什么代码,只需要新增这 个类即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值