草庐IT

封装继承多态

lingstar 2023-03-28 原文

面向对象三大特征:封装、继承、多态

访问控制符

  • 在讲封装之前我们先了解一下关于访问控制符

​ Java 提供了 3 个访问控制符:private、 protected 和 public ,代表 3 种不同的访问级别,再加上一个默认的访问控制级别(不使用任何访问控制符),共有 4 个访问控制级别。

  • private(当前类访问权限):类中的一个的成员被 private 修饰,它只能在当前类的内部被访问;
  • default(包访问权限):类中的一个成员或者一个外部类不使用任何访问控制符修饰,它能被当前包下其他类访问;
  • protected(子类访问权限):类中的一个的成员被 protected 修饰,它既可以被当前包下的其他类访问,又可以被不同包的子类访问;
  • public(公共访问权限):类中的一个成员或者一个外部类使用 public 修饰,它能被所有类访问。

我们可以用一个表,来看一下访问修饰符

一个类中 同一个包中 其他包的子类中 全局范围
private
default
protected
public

看完了修饰符,我么开始学习封装

封装

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

封装的定义

封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。

封装的意义

  • 1.提高代码的安全性,保护数据
  • 2.隐藏代码的实现细节
  • 3.统一接口
  • 4.增加系统可维护性

下面我们用代码来实际看一下关于封装的应用:

首先定义一个学生类,在类中我们定义了三个属性,但是属性的修饰符是private

也就是私有的,我们只能在类中去使用这个方法,那么我们在测试类中想要调用它,这时我们可以定义一个公共的方法来使用它

public class Student {
    //private关键字,定义私有属性
    //名字
    private String name;
    //学号.
    private String id;
    //性别
    private String sex;
   }
public class Student {
    //private关键字,定义私有属性
    //名字
    private String name;
    //学号.
    private String id;
    //性别
    private String sex;
  //通过get用来获取类中的name
public String getName() {
    return this.name;
}
//set给这个属性设置值

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

现在我们可以在测试类中,看一下,

public class Application {
    public static void main(String[] args) {
        Student student=new Student();
        student.setName("lingstar");
        System.out.println(student.getName());
    }

}

输出:

lingstar

我们在操作中也可以使用快捷键,AIL+INSERT然后点击Getter或者Setter或者Getter and Setter来快速添加此方法

封装可以也可以对传入其中的数据进行判断,看数据是否合理?

eg:以传入的性别为例

性别只有男或者女,当传入性别为其他时候,我们返回"您输入的性别有误"

我们在类中添加一下代码

代码:

public String getSex() {
    return sex;
}

public void setSex(String sex) {
    switch (sex) {
        case " 男":
            this.sex = sex;
            break;
        case "女":
            this.sex=sex;
            break;
        default:
            System.out.println("您输入的性别有误!");
    }
}

然后实际运行看一下:

测试代码:

public class Application {
    public static void main(String[] args) {
        Student student=new Student();
        student.setSex("what");
        System.out.println(student.getSex());
    }

}

输出:

您输入的性别有误!
null

当输入正确的信息时:

public class Application {
    public static void main(String[] args) {
        System.out.println(student.getName());
        student.setSex("男");
        System.out.println(student.getSex());
    }

}

输出:

通过这么一个简单的例子,想要了解全部的封装的意义不太现实,这就需要我们在空闲时间多去练习和使用封装!

继承

  • Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。

  • Java 使用 extends 作为继承的关键字子类继承了父类,就会获得父类的全部成员变量和方法

  • java只有单继承没有多继承

  • 私有的(private)东西是无法继承的

代码示例:

我们首先定义一个Person类

public class Person {
    public void run(){
        System.out.println("人会奔跑");
    }
}

然后定义一个Student类,让学生类继承Person类

public class Student extends Person{

}

在测试类中调用一下这个学生类,看能否输出它父类的方法!

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

            Student student=new Student();
            student.run();
      }

    }

在java中所有的类都继承Object类

输出一下看是否调用Person中的run方法

人会奔跑

可以用ctrl+h看一下结构

我们可以看到Person类继承于Object类,然后Studet

又继承Person类

super

​ super在java中两种用法

  • 在子类中调用父类的属性或方法

​ 因为在java中子类没办法直接调用父类的方法或属性,如果想要调用,必须使用java关键字!

写个简单的代码实际体验一下java关键字

先定义Person类:

public class Person {
    protected String name="star";

}

然后定义一个学生类,让学生类继承这个类:

public class Student extends Person{
    public String name="lingstar";
    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }

}

定义测试类,用来输出结果

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

    }

输出:

星星
lingstar
star
  • 在子类中调用父类构造器

​ 在Java中,子类是父类的派生类,它的实例化依赖于父类的实例化。所以它的任何一个构造函数都必须要初始化父类,Java就是super关键字调用父类构造方法,且调用父类的无参构造必须放在第一行!

person类:

public class Person {
    public Person(){
        System.out.println("调用了person的无参构造");
    }
}

student类:

public class Student extends Person{
public Student(){
    System.out.println("调用了Student的无参构造");
}
}

直接实例化student看一下,代码是怎样执行的!

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

输出结果:

调用了person的无参构造
调用了Student的无参构造

从结果可以看出,是先调用了父类的无参构造方法,再调用子类的无参构造。

也就相当于是

public Student(){
    super();
    System.out.println("调用了Student的无参构造");
}
}

在studen中是这样执行的。先调用父类的构造器,且super只能放在第一行,放在下面会报错!

super总结:

1.super调用父类的构造方法,必须在构造方法的第一个!

2.super必须只能出现在子类的方法或构造方法中!

3.super和this不能同事调用构造方法!

super与this的区别:

代表的对象不同 前提条件 构造方法
this 代表本身调用这个对象 没继承也可以使用 this()本类的构造
super 代表父类对象的应用 只能在继承条件中使用 super()父类的构造

方法的重写

​ 在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

注意:重写都是方法的重写与属性无关

eg:

定义一个A类和B类,让A继承B类,里面有一个相同的方法,输出先看一下效果

public class A extends B{
    @Override//注解:有功能的注解
    public void test(){
        System.out.println("A=>test()");
    }
}
public class B {
    public void test(){
        System.out.println("B=>test()");
    }
}

测试类:

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

    }

输出:

A=>test()
B=>test()

我们把static去掉,看一下方法的重写

public class A extends B{
    @Override//注解:有功能的注解
    public void test(){
        System.out.println("A=>test()");
    }
}

再运行看一下结果:

A=>test()
A=>test()

因为静态方法(加 static)是类的方法,而非静态是对象的方法。

有static时,b调用了B类的方法,因为b是用B定义的。

没有static时,b调用的是对象的方法,而b是用A类new的。

重写小结

​ 1.重写需要有继承关系,子类重写父类的方法

​ 2.子类与父类的方法名必须相同,方法体不同

​ 3.参数列表必须相同

​ 4.修饰符的范围可以扩大

​ 5.抛出的异常:范围可以被缩写,但不能扩大:ClassNotFoundException-->Exception(大)

​ 6.重写快捷键AIL+INSERT:Override

为什么要重写?

​ 因为有时父类的功能,子类不一定需要,或者不一定满足

多态

什么是多态?

多态就是同一个行为具有多个不同表现形式或形态的能力。多态只是方法的多态,属性没有多态!

多态存在的条件

​ 1.继承关系,需要有父子类之间的联系

​ 2.方法需要被重写

​ 这些不能重写:

​ static 方法,属于类,不属于示例

​ fianl 常量

​ private修饰

​ 3.父类引用指向子类对象

代码实现

接下来通过代码来体会一下:

先写一个Person类,让他作为Student类的父类

public class Person {
    public void run(){
        System.out.println("人会快速跑");
    }
}

再写Student类,继承Person类,且在Student类中重写Person类的方法

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("人也会慢跑");
    }
}

然后再通过测试类来看一下

public class Application {
        public static void main(String[] args) {
            //一个对象的实际类型是确定的
//            new Student();
//            new Person();

//          可以指向的引用类型就不确定了:父类的引用指向子类
            //对象能执行哪些方法,主要看对象左边的类型,和右边关系不大!
            //student能调用的方法都是自己的或者父类的
            Student s1=new Student();
            //Person虽然可以指向子类,但是不能调用子类独有的方法
            Person s2=new Person();
            Object s3=new Student();//如果子类重写了父类,调用子类,如果子类没有重写就调用父类
            s2.run();
            //如果我在子类Student中写一个方法,而用s2去调用是调用不出来的!
            s1.run();

      }

    }

输出:

人会快速跑
人也会慢跑

有关封装继承多态的更多相关文章

  1. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  2. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

  3. ruby-on-rails - 为什么 DataMapper 使用混合与继承? - 2

    所以我只是对此感到好奇:DataMapper为其模型使用混合classPostincludeDataMapper::Resource虽然active-record使用继承classPost有谁知道为什么DataMapper选择这样做(或者为什么AR选择不这样做)? 最佳答案 它允许您从另一个不是DM类的类继承。它还允许动态地将DM功能添加到类中。这是我正在处理的模块中的类方法:defdatamapper_classklass=self.dupklass.send(:include,DataMapper::Resource)klass

  4. ruby-on-rails - Ruby on Rails 单表继承(STI)和单元测试问题(使用 PostgreSQL) - 2

    我正在使用带有单个“帐户”表的STI模型来保存用户和技术人员的信息(即用户...8)错误:test_the_truth(用户测试):ActiveRecord::StatementInvalid:PGError:ERROR:关系“技术人员”不存在:从“技术人员”中删除...从本质上讲,标准框架不承认Technicians和Users表(或PostgreSQL称它们为“关系”)不存在,事实上,应该别名为Accounts。有什么想法吗?我对RoR比较陌生,不知道如何解决这个问题而又不完全删除STI。 最佳答案 原来问题是由于存在:./te

  5. ruby - 为什么 Ruby 模块继承不像类继承那样工作? - 2

    假设我有一个名为Flight的模块,其中包含类方法和实例方法。我可以使用include、extend或两者将其方法放入类中:classBatinclude会将Flight添加到Bat.ancestors,但extend不会。我的问题是,为什么模块与类不同?当我对Mammal进行子类化时,我总是同时获得类和实例方法。然而,当我混入一个模块时,我不能同时获得类和实例方法(除非我使用self.included钩子(Hook)或类似ActiveSupport::Concern的东西)。这种差异背后是否存在语言设计问题? 最佳答案 Modul

  6. ruby - 为什么 Object 在 Ruby 中既包含内核又继承它? - 2

    在Ruby(1.8.X)中为什么Object既继承了内核又包含了内核?仅仅继承还不够吗?irb(main):006:0>Object.ancestors=>[Object,Kernel]irb(main):005:0>Object.included_modules=>[Kernel]irb(main):011:0>Object.superclass=>nil请注意,在Ruby1.9中情况类似(但更简洁):irb(main):001:0>Object.ancestors=>[Object,Kernel,BasicObject]irb(main):002:0>Object.included

  7. Ruby 获取继承类 - 2

    我正在为Rails创建我的第一个插件。我对ruby​​还是很陌生,我想知道是否有可能获得继承类?例如,我正在尝试创建一个插件,在您不使用迁移时允许进行单元测试和功能测试。我要做的是初始化一个名为controller的类变量,以初始化为正在测试的Controller类型。如果我有一个基类ControllerTest:classControllerTest所以我目前坚持的是获取继承类的名称。这可能吗?如果没有,有没有人知道我可以如何着手实现它的另一种方式?提前致谢。 最佳答案 非常简单:使用“继承”回调。来自Class类的RDoc:in

  8. ruby - ActiveRecord,通过多态属性查找 - 2

    有这个:classEventtrueenduser=User.create!我可以:Event.create!(:historizable=>user)但我不能:Event.where(:historizable=>user)#Mysql2::Error:Unknowncolumn'events.historizable'in'whereclause'我必须改为这样做:Event.where(:historizable_id=>user.id,:historizable_type=>user.class.name)更新重现问题的代码:https://gist.github.com/fg

  9. ruby-on-rails - 是吗? Rails 3 中的单表继承失败 - 2

    Object#is_a?在Rails3中以最奇怪的方式失败。我将单表继承设置如下(为简洁起见进行了简化):#resource.rbclassResource在我的Controller中,我有这个:defcreate@resource=Resource.findparams[:resource_id]logger.info'@resourceclass:'+@resource.class.namelogger.info'@resourcesuperclass:'+@resource.class.superclass.namelogger.info'@resourceis_a?(Video

  10. ruby-on-rails - Rspec Controller 在 Rails 中测试继承自 AbstractController::Base 的 Controller - 2

    我正在为我未构建的应用程序编写Controller测试,因此这绝对是一个学习过程。这是我第一次遇到直接继承自AbstractController::Base的Controller。显然,它的行为与其他Controller不同。其格式大致为:classSchwadGenericController我尝试了正常测试,这是我目前要让任何事情发生的地方。require'rails_helper'describeSchwadGenericControllerdo#before(:each)do#SchwadGenericController.skip_authorize_resource#end

随机推荐