Java面向对象特征1之封装与隐藏

1 - 为什么需要封装、封装的作用和含义?

/*
我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部结构吗?有必要碰电动机吗?

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

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想
*/

 

1-面向对象的特征1:封装与隐藏

/*面向对象的特征1:封装与隐藏
 * 
 * 1-问题的引入:
 *         当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值,这里赋值操作要受到属性数据类型和存储
 *         范围的制约,除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值,介入额外的限制条件,这个条件就不
 *         能在属性声明时体现。
 *         同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值,则需要将属性声明为私有的(private)
 *         -->此时,针对属性就体现了封装性。
 * 2-封装性的体现
 *         类的属性abc私有化(private),同时,提供公共的(public)方法来获取(getAbc)和设置(setAbc)此属性的值
 * 
 * 3-扩展:①如上 ② 不对外暴露私有的方法 ③ 单例模式
 * 
 */
public class EncapsulationTest {

    public static void main(String[] args) {
        // 实例化
        Animal animal = new Animal();
        animal.name = "大黄";
        // animal.age = 1; 不能再访问
        // animal.legs = 4;
        animal.setLegs(4);
        
        animal.show();
        // animal.legs = -4;
        animal.setLegs(-2); // 0
        animal.show();
        
        // 访问私有属性
        int legNumber = animal.getLegs();
        System.out.println(legNumber);
    }
}

class Animal{
    String name;
    // int age;
    private int age;
    // int legs;  腿的个数
    private int legs; // 设置私有的权限修饰符,这样除自身作用域外,不能访问到此属性
    
    public void eat() {
        System.out.println("动物进食");
    }
    public void show() {
        System.out.println("name:"+name+"\nage:"+age+"\nlegs:"+legs);
    }
    public void setLegs(int i) {
        if(i > 0 && i % 2 == 0) {
            legs = i;
        }else {
            legs = 0;
            // 也可以抛出异常(后面介绍)
        }
    }
    // 对象属性获取
    public int getLegs() {
        return legs;
    }
    // 提供关于age属性get和set方法,外部才能访问到此属性
    public int getAge() {
        return age;
    }
    public void setAge(int i) {
        if(i > 0) {
            age = i;
        }else {
            // 抛出异常
            age = 18;
        }
    }
}
封装与隐藏

2-封装性的体现:需要权限修饰符的来配合。

  ①Java规定的4种权限(从小到大排列):private,缺省(什么都不写),protected,public
  ②4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
  ③具体的,4中权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类。修饰类的话只能使用:缺省、public

2 - 四种访问权限修饰符

 

 

3 - 总结封装性

Java提供4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

封装性的4个体现:

体现1:将类的属性私有化(private),提供公共的方法(public)来获取(get)和设置(set)此属性的值

public String getName(){

  return this.name;

}

public void setName(String name){

  this.name = name;

}

体现2:不对外暴露的私有方法

体现3:单例模式(将构造器私有化 )

体现4:如果不希望类在包外被调用,可以将类设置为缺省的

4 - 封装与隐藏练习

/*
创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。

在PersonTest类中示例华Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
*/

package com.Encapsulation.test;
/*
 * 创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
 * 用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。
 * 
 */
public class Person {
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int i) {
        if(i > 0 && i < 130) {
            age = i;
        }else {
            // 抛出异常,这里设置成-1,表示不合法
//            age = -1;
            throw new RuntimeException("传入的数据不合法!");
        }
    }
}
Person.java
package com.Encapsulation.test;
/*
 * 在PersonTest类中示例华Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
 */
public class PersonTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Person person = new Person();
        person.setAge(22); // 设置年龄
        
        int personAge = person.getAge(); // 获取年龄
        System.out.println(personAge);
        
        // person.age = 22; 编译不通过

    }
}
PersonTest.java

5 - 类的成员之构造器

/*
类的结构之一:属性
类的结构之二:方法
类的结构之三:构造器(或构造方法、constructor)的使用

1-构造器的作用:
  ①创建对象
  ②给对象进行初始化

2-说明
  ①如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器
  ②定义构造器的格式:权限修饰符 类名(形参列表){}
  ③一个类中定义的多个构造器,彼此构成重载
  ④一旦我们显示的定义了类的构造器之后,系统就不在提供默认的空参构造器
  ⑤一个类中至少有一个构造器
*/

3-代码示例

public class PersonTest{
    public static void main(String[] args) {
        // 创建类的对象:new + 构造器
        Person p = new Person();
        p.eat();
        
        Person p1 = new Person("howie",22); // 使用构造器
        p1.study();
    }
}

class Person {
    // 属性
    String name;
    int age;
    
    // 构造器
    public Person(){ // 构造器1
        System.out.println("执行构造器呀。");
    }
    public Person(String s) { // 构造器2
        name = s;
    }
    public Person(String s,int i) { // 构造器3
        name = s;
        age = i;
    }
    
    // 方法
    public void eat() {
        System.out.println("人吃放!");
    }
    public void study() {
        System.out.println("人要学习!");
    }
}
构造器的创建与使用

6 - 构造器+封装+隐藏的练习

/*
编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
*/

package com.company;
/*
 * 编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。
 * 此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
 */
public class TriAngle {
    private double base; // 底边长
    private double height; //

    public TriAngle(){
    }
    public TriAngle(double i,double h){
        base = i;
        height = h;
    }

    public double getBase(){
        return base;
    }
    public void setBase(double i){
        base = i;
    }
    public void setHeight(double h){
        height = h;
    }
    public double getHeight(){
        return height;
    }
}
TriAngle.java
package com.company;

public class TriAngleTest {
    public static void main(String[] args) {
        // 方法1
        TriAngle t1 = new TriAngle();
        System.out.println("base="+t1.getBase()+"\theight="+t1.getHeight());
        t1.setBase(4);
        t1.setHeight(3);
        double s1 = (t1.getBase() * t1.getHeight()) / 2;
        System.out.println("方法1\t三角形的面积="+s1);

        // 方法2
        TriAngle t2 = new TriAngle(4,3);
        System.out.println("base="+t2.getBase()+"\theight="+t2.getHeight());
        double s2 = (t1.getBase() * t1.getHeight()) / 2;
        System.out.println("方法2\t三角形的面积="+s2);
    }
}
TriAngleTest.java

7 - 属性赋值的过程

/*
截止到目前,我们已经血量很多位置可以对类的属性赋值。现总结这几位位置,并指明赋值的先后顺序。

赋值的位置
  ①默认初始化
  ①显示初始化
  ③构造器中初始化
  ④通过"对象.属性"或"对象.方法"的方式赋值

赋值的先后顺序:
① - ② - ③ - ④
*/

/*
 * 总结属性赋值的先后顺序
 *
 * 结论:1 - 2 - 3 - 4
 */
public class UserTest {
    public static void main(String[] args) {
        // 验证1 默认初始化为0
        // 验证2 显示赋值
        User u1 = new User();
        System.out.println(u1.age); // 1

        // 验证3 构造器中赋值
        User u2 = new User(2);
        System.out.println(u2.age); // 2

        // 验证4 通过"对象.属性"或"对象.方法"的方式赋值
        User u3 = new User();
        u3.setAge(22);
        System.out.println(u3.getAge());
    }
}

class User{
    String name;
    int age = 1;

    // 设置构造器
    public User(){
    }
    public User(int i){
        age = 2;
    }
    // 设置方法
    public void setAge(int i){
        age = i;
    }
    public int getAge(){
        return age;
    }
}
代码验证

8 - 知识扩展

JavaBean

  1 JavaBean是一种Java语言写成的可重用组件。
  2 所谓javaBean,是指符合如下标准的Java类:

    ✔ 类是公共的

    ✔ 有一个无参的公共的构造器

    ✔ 有属性,且有对应的get、set方法
  3 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用 户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关 心任何改变。

/*
 * JavaBean是一种Java语言写成的可重用组件,所谓JavaBean,是指符合以下标准的Java类:
 *         ①类是共共的
 *         ②有一个无参的公共的构造器
 *         ③有属性,且有对应的get、set方法
 */
public class Customer {
    private int ID;
    private String name;

    public Customer(){
    }
    public void setID(int ID){
        this.ID = ID;
    }
    public int getID(){
        return ID;
    }
    public void setName(String s){
        this.name = s;
    }
    public String getName(){
        return name;
    }
}
代码示例

9 - this关键字

1-什么是this?

 

  1Java中,this关键字比较难理解,它的作用和其词义很接近。

    ✔ 它在方法内部使用,即这个方法所属对象的引用;

    ✔ 它在构造器内部使用,表示该构造器正在初始化的对象。

  2 this 可以调用类的属性、方法和构造器

  3 什么时候使用this关键字呢?

    ✔ 当在方法内需要用到调用该方法的对象时,就用this。 具体的:我们可以用this来区分属性局部变量。 比如:this.name = name;

 

2-this(当前对象)关键字的使用
  1-this可以用来修饰:属性、方法、构造器

  2-this修饰属性和方法:首先this理解为 当前对象 或 当前正在创建的对象
    ①在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法,但是我们 通常省略 this。特殊的如果方法的形参和类的属性同名时,则不能省略必须使用"this.属性"表明此变量是属性,而非形参。

    ②在类构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法,但是我们 通常省略 this。特殊的如果构造器的形参和类的属性同名时,则不能省略,必需使用 "this.属性" 表明此变量是属性,而非形参。

3-this调用构造器
  ① 我们在类的构造器中,可以显示的使用"this(形参列表)"方式,调用本类中指定的其他构造器
  ② 构造器中不能通过"this(形参列表)"方式调用自己
  ③如果一个类中有n个构造器,则最多有n - 1构造器中使用了"this(形参列表)"
  ④规定:"this(形参列表)"必须声明在当前构造器的首行
  ⑤构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器

public class PersonTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Person p1 = new Person("howie");
        p1.setAge(22);
        System.out.println(p1.getAge());
        
        // p1.eat();
        
        Person p2 = new Person("alex",18);
        int res = p2.getAge();
        System.out.println(res);

    }
}

class Person{
    private String name;
    private int age;
    
    // 构造器
    public Person() {
        System.out.println("111111111111111111111111111111");
    }
    public Person(String name) {
        this();
        this.name = name;
    }
    public Person(int age) {
        this();
        this.age = age;
    }
    public Person(String name,int age) {
        this(age);
        this.name = name;
        // this.age = age;
    }
    
    // 方法
    public void setName(String name) {
        this.name = name; // this修饰属性
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age; // this修饰属性
    }
    public int getAge() {
        return age;
    }
    public void eat() {
        System.out.println("人吃饭");
        this.sleep(); // this修饰方法
    }
    public void sleep() {
        System.out.println("人睡觉");
    }
}
代码示例

10 - package 和 imort 关键字的使用

// package com.company;

/*
 * 1-package关键字的使用
 *     ①为了更好的实现项目中类的管理,提供包的概念
 *     ②使用package声明类或接口所属的包,声明在源文件的首行
 *     ③包,属于标识符,遵循标识符的命名规则,规范(小写),见名知意
 *     ④每"."一次,就代表一层文件目录
 * 注意:同一个包下,不能命名同名的接口、类,不同包下,可以命名同名的接口、类
 * 
 * 2-import(导入) 关键字的使用
 *     ①在源文件中显示的使用import结构导入指定包下的类、接口
 *     ②声明在包的声明和类的声明之间
 *     ③如果需要导入多个结构,则并列写出即可
 *     ④可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构
 *     ⑤如果使用的类或接口是java.lang包下定义的,则可以省略import结构
 *     ⑥如果使用的类或接口是本包下定义的,则可以省略import结构
 *     ⑦如果在源文件中,使用了不同包下同名的类,则必须至少有一个类需要以全类名的方式显示(import com.company.类名;)
 *     ⑧使用"xxx.*"的方式表示可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显示全类名
 *     ⑨import static 导入指定类或接口中的静态结构
 */
import java.util.Arrays; // import 的使用

public class PackageImportTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String info = Arrays.toString(new int[] {1,2,3});
        System.out.println(info); // [1, 2, 3]
        
        PersonTest personTest = new PersonTest();
    }

}
View Code

11 - MVC设计模式

 

流程解析

 

posted @ 2020-05-31 09:38  赖正华  阅读(327)  评论(0编辑  收藏  举报