面向对象的特性一:封装性

1.封装性的理解

  • 为什么需要封装?封装的作用和含义?
    我们要用洗衣机,只需要按一下开关和洗涤模式就可以了。没必要了解洗衣机内部的结构,没必要碰电动机…
  • 设计程序追求“高内聚,低耦合”
    高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
    低耦合:仅对外暴露少量的方法用于使用
  • 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。

1、 问题的引入:当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件,这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如setLegs)。同时,我们需要避免用户再次使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的(private),此时,针对于属性就体现了封装性。
2、 封装性的体现:
体现一:我们将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXXX)和设置(setXXX)此属性的值。
别的体现:①如上,②不对外暴露的私有方法,③单例模式,…
3、总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

通过一个例子体会封装性

public class AnimalTest{
    
    
	public static void main(String[] args){
    
    
		Animal a = new Animal();
		a.name = "大黄";
		a.age = 1;
		a.setLegs = 4;
		a.legs = 4;//报错:The field Animal.legs is not visible
		
	}
}

class Animal{
    
    
	String name;
	private int age;//将age私有化
	private int legs;//腿的个数
    //对legs进行了封装(隐藏),使得外部不能直接调用legs,必须通过setLegs方法调用
    //设置leg属性
	public void setLegs(int l){
    
    
		if(l >= 0 && l %2 == 0){
    
    
			legs = l;
		}else{
    
    
			legs = 0;//或者提示异常,暂时未讲
		}
	}
	//获取leg属性
	public int getLegs(){
    
    
		return legs;
	} 

	//提供关于属性age的set和get方法
	 //设置age属性
	public void setAge(int a){
    
    
		age = a;
	}
	//获取age属性
	public int getAge(){
    
    
		return age;
	} 

	public void eat(){
    
    
		System.out.println("动物进食");
	public void show(){
    
    
		System.out.println("name = " + name + ",age = " + age + ",legs = " + legs);
	}
	}
}

2. 四种权限修饰符

封装性的体现,需要权限修饰符来配合。
Java权限修饰符public、protected、private置于类的成员定义前,用来限定对象对该类成员的访问权限。

  1. Java规定的4种权限(从小到大排列):private、缺省(default)、protected、public
  2. 四种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
  3. 四种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类;对于类,只可以用public和缺省(default)修饰
  4. public类可以在一个项目中任意地方被访问,缺省类只可以被同一个包内部的类访问。
修饰符 内部类 同一个包 不同包的子类 同一个项目
private
缺省
protected
public
public class PersonTest{
    
    
	public static void main(String[] args){
    
    
		Person p = new Person();
		p.setAge(5);
		p.getAge();
		System.out.println("年龄为: " + p.getAge());
	}
}

class Person{
    
    
	private int age;

	public void setAge(int i){
    
    
		if(i >= 0 && i <= 130){
    
    
			age = i;
		}else{
    
    
			throw new RuntimeException("传入的数据不合理!")//抛出异常
		}
	}
	public int getAge(){
    
    
		return age;
	}
}

3. 类的成员之三:构造器

类的结构之三:构造器(或构造方法,constructor)

1、构造器的作用:

  • 创建对象
  • 初始化对象的属性

2、说明:

  • 如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器(此时构造器的权限与该类的权限相同)
  • 一旦显示定义了类的构造器之后,系统就不再提供默认的空参构造器
  • 一个类中,至少会有一个构造器。
  • 定义构造器的格式:权限修饰符 类名(形参列表){}
  • 一个类中定义的多个构造器,彼此构成重载

3、构造器的特征

  • 它具有与类相同的名称
  • 它不声明返回值类型。(与声明为void不同)
  • 不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值
public class PersonTest{
    
    
	public static void main(String[] args){
    
    
	//创建Person类的对象:new + 构造器
	Person p = new Person();//调用的是构造器
	p1.talk();
	Person p1 = new Person("Tom");//创建对象,并给对象进行初始化
	System.out.println(p1.name);
	
class Person{
    
    
	//属性
	String name;
	int age;

	//构造器
	public Person(){
    
    
		System.out.println("Person()......");
	}
	public Person(String n){
    
    
		name = n;
	}
	//方法(或函数)
	public void talk(){
    
    
		System.out.println("人讲话");
	}
}

练习1:
在这里插入图片描述

package Constructor;

public class PersonTest{
    
    
    public static void main(String[] args){
    
    
        //创建Person类的对象:new + 构造器
        Person p = new Person("Tom",21);//调用的是构造器
        System.out.println("name = " + p.getName() + ",age = " + p.getAge());
    }
}
class Person{
    
    
    //属性
    private String name;
    private int age;

    //构造器
    public Person(){
    
    
        age = 18;
    }
    public Person(String n,int a){
    
    
        name = n;
        age = a;
    }

    //方法(或函数)
    //设置name属性
    public void setName(String n){
    
    
        name = n;
    }
    //获取name属性
    public String getName(){
    
    
        return name;
    }
    public void setAge(int i){
    
    
        age = i;
    }
    public int getAge(){
    
    
        return age;
    }
}


练习2:
在这里插入图片描述

package Constructor;

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

        TriAngle t = new TriAngle(5,3);
        TriAngle t1 = new TriAngle();

    }
}
class TriAngle{
    
    
    //属性
    private double base;//底边
    private double height;//高

    //构造器
    public  TriAngle(){
    
    

    }
    public TriAngle(double b,double h){
    
    
        base = b;
        height = h;
        double area = (b * h)/2;
        System.out.println("三角形的面积为:" + area);
    }

    //公共方法(或函数)
    public void setBase(double b){
    
    
        base = b;
    }
    public double getBase(){
    
    
        return base;
    }
    public void setHeight(int h){
    
    
        height = h;
    }
    public double getHeight(){
    
    
        return height;
    }
}

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

  • 类是公共的
  • 有一个无参的公共的构造器
  • 有属性,且有对应的get、set构造方法

拓展知识2:UML类图
在这里插入图片描述
知识3:属性赋值的先后顺序
①默认初始化——②显式初始化——③构造器中初始化——④通过“ 对象.属性” 或 “对象.方法” 的方式赋值

4. this关键字

this关键字的使用:

  1. this可以用来修饰属性、方法、构造器。
  2. this修饰属性和方法:
    this理解为:当前对象 或 当前正在创建的对象(主要适用于构造器)
    2.1 在类的方法中,我们可以使用 “this.属性” 或 “this.方法” 的方式,调用当前对象的属性或方法。但是,通常情况下,我们都选择省略 “this.” 。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用 “this.变量”的方式,表明此变量是属性,而非形参。
    2.2 在类的构造器中,我们可以使用 “this.属性” 或 “this.方法” 的方式,调用当前正在创建的对象的属性或方法。但是,通常情况下,我们都选择省略 “this.” 。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用 “this.变量”的方式,表明此变量是属性,而非形参。
  3. this调用构造器
    ① 我们在类的构造中,可以显示的使用 “this(形参列表)” 的方式,调用本类中指定的其他构造器
    ② 构造器中不能通过 “this(形参列表)” 的方式调用自己(否则会死循环)
    ③ 如果一个类中有n个构造器,则最多有n - 1 个构造器中使用了 “this(形参列表)”(构造器a调用了构造器b后,构造器b不能再调用构造器a,否则也会死循环)。
    ④ 规定:“this(形参列表)” 必须声明在当前构造器的首行
    ⑤ 构造器内部:最多只能声明一个 “this(形参列表)” ,用来调用其他的构造器
package Constructor;

public class PersonTest{
    
    
    public static void main(String[] args){
    
    
        Person p1 = new Person();
        p1.setAge(8);
        p1.getAge();
        System.out.println(p1.getAge());
    }
}
class Person{
    
    
    private String name;
    private int age;

    //构造器
    public Person(){
    
    
    }
    public  Person(String name){
    
    
        this();//调用空参构造器
        this.name = name ;
    }

    //方法
    public void setName(String name){
    
    
        this.name = name;//this可以理解为当前对象,this.name即为当前对象的属性
    }
    public String getName(){
    
    
        return name;//或return this.name;
    }
    public void setAge(int age){
    
    
        this.age = age;
    }
    public int getAge(){
    
    
        return age;//或return this.age;
    }
    public  void eat(){
    
    
        System.out.println("人可以吃饭");
        study();//或this.study();方法中调用方法
    }
    public  void study(){
    
    
        System.out.println("人可以学习");
    }

}


练习:
在这里插入图片描述

public class BoyGirl {
    
    
    public static void main(String[] args) {
    
    
        Boy boy = new Boy();
        Girl girl = new Girl();
        girl.setName("lisa");
        boy.marry(girl);
    }
}
package Constructor;

public class Boy {
    
    
    private String name;
    private int age;

	//构造器
	public Boy(){
    
    
	}
	public Boy(String name,int age){
    
    
		this.name = name;
		this.age = age;
	}

    public void setName(String name) {
    
    
        this.name = name;
    }
    public String getName(){
    
    
        return this.name;
    }
    public void setAge(int age){
    
    
        this.age = age;
    }
    public int  getAge(){
    
    
        return this.age;
    }
    public void marry(Girl girl){
    
    
        System.out.println("我想娶" + girl.getName() );
    }
    public void shout(){
    
    
        if(this.age >= 22){
    
    
            System.out.println("你可以结婚了");
        }else{
    
    
            System.out.println("你不能结婚");
        }

    }
}

package Constructor;

public class Girl {
    
    
	//属性
    private String name;
    private int age;
    
	//构造器
	public Girl(){
    
    
	}
	public Girl(String name,int age){
    
    
		this.name = name;
		this.age = age;
	}
    public void setName(String name) {
    
    
        this.name = name;
    }
    public String getName(){
    
    
        return this.name;
    }
    public void marry(Boy boy){
    
    
    	System.out.println("我想嫁给" + boy.getName() );
      	boy.marry(this);//this表示当前对象,谁调marry,boy就娶谁

	//比较两个对象的大小
	//return: 正数:当前对象大,负数:当前对象小,0:当前对象与形参对象相等
	//当前对象指调用compare方法的对象,形参对象为传递的形参
    public void compare(Girl girl){
    
    
		if(this.age > girl.age){
    
    //this.age为调compare方法的对象的属性,girl.age为为形参的属性
			return 1;
		}else if(this.age < girl.age){
    
    
			return -1;
		}else{
    
    
			return 0;
		}
    }
}

5. package关键字

一、package关键字的使用

  1. 为了更好地实现项目中类的管理,提出包的概念
  2. 使用package声明类或接口所属的包,声明在源文件的首行
  3. 包,属于标识符,遵循标识符的命名规则和规范,“见名知意”(xxyyzz)
  4. 每 ”.“ 一次,就代表一层文件目录。
  5. 同一个包下,不能命名同名的接口、类;
    不同的包下,可以命名同名的接口、类
    在这里插入图片描述
    体会:一个项目可能涉及到的类非常多,可以将类分到不同的包里,整体来看有很多包,当项目哪块出问题了,就去相应的包下去找,这样就使整个项目的结构变得很清晰。
    在这里插入图片描述

6. import关键字

一、import关键字的使用
import:导入

  1. 在源文件中,显式使用import结构导入指定包下的类、接口
  2. 声明在包的声明和类的声明之间
  3. 如果需要导入多个结构(类、接口),则并列写出即可
  4. 可以使用 “xxx.*” 的方式,表示可以导入xxx包下的所有结构
  5. 如果使用的类、接口是java.lang包下定义的,则可以省略import结构
  6. 如果使用的结构是本包下定义的,也可以省略import结构
  7. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全命名(包含包的路径在内的完整的路径名)的方式(例如:com.weiwei.exer1.Account acc1 = new com.weiwei.exer1.Account() )
  8. 使用 “xxx.* ”方式表明可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显式导入子包
  9. import static:导入指定类或接口中的静态结构(落脚点为属性、方法;不是类、接口)

猜你喜欢

转载自blog.csdn.net/weixin_46138661/article/details/112802121