一、private实现封装
封装(encapsulation,有时也称数据隐藏)是与对象有关的一个重要概念。对象中的数据称为实例域(instance field),操纵数据的过程称为方法。所谓封装,也就是把客观事物封装成抽象的类,并且类可以把⾃⼰的数据和⽅法只让可信的类或者对象操作,对不可信的进⾏信息隐藏。简⽽⾔之就是,内部操作对外部⽽⾔不可⻅(保护性)。
首先看一个无封装范例:
class Employee {
String name;
int age;
double salary;
public void get() {
System.out.println("名字" + name + "年龄" + age + "薪资" + salary);
}
}
public class Demo3{
public static void main(String[]args){
Employee person1=new Employee();
person1.name="king";
person1.age=-28;
person1.salary=100000;
person1.get();
}
}
运行结果:
结果我们看见人的年龄是-28,这是由于对象可以在类的外部直接访问属性。为了避免此类问题,让内部操作对外不可见(对象不能直接操作属性),可以使用private进行封装。
private String name;
private int age;
private double salary;
此时使用private对属性进行了封装,要访问私有私有属性,那么按照要求,需要定义属性相应的1、setter 2、 getter方法
1、setter方法:主要用于属性内容的设置与修改(注意有参数)
public void setName(String name)
2、getter方法:主要用于属性内容的取得(没有参数)
public String getName()
为封装属性设置getter、setter方法
class Employee {
private String name;
private int age;
private double salary;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public void get() {
System.out.println("名字" + name + "年龄" + age + "薪资" + salary);
}
}
public class Demo3{
public static void main(String[]args){
Employee person1=new Employee();
person1.setName("king");
person1.setAge(-28);
person1.setSalary(100000);
person1.get();
}
}
结果如下:
此时我们发现private封装最大的特点就是只允许本类访问而不允许外部类访问。然而此时人的年龄是负数,需要加入检查逻辑错误的代码,可以在setter中增加验证,如果值为正则赋值,为负则默认0:
public void setAge(int age) {
if(age>0){
this.age=age;
}
}
结果如下:
对于数据验证,在java标准开发中应该由辅助代码完成,在实际开发中,setter一般只是简单的设置属性内容,getter只是简单的取得属性内容。
类的设计原则:编写类时,类中的所有属性必须用private封装。
属性若要被外部访问,则必须定义getter、setter方法。
二、构造方法
先来看对象的产生格式:
①类名称 ②对象名称 = ③new ④类名称();
根据以上定义做以下分析:
①任何对象都有对应的类,类是对象的蓝图,即规定了对象的类型(对象可以使用哪些属性和方法是由类定义的)。
②要使用对象,需要一个名称,这是唯一的一个标记,引用一块堆内存。
③开辟新的堆内存空间。
④调用了名称和类名称相同的方法,这就是构造方法。
结论:所谓的构造方法就是关键字new实例化新对象时来调用的操作方法。
对于构造方法的定义·,也需要遵循以下原则:
(1)方法名称必须与类名称相同
(2)构造方法没有返回值类型声明
(3)每一个类中必须至少定义一个构造方法(没有明确定义,则系统自动生成一个无参构造)
范例:一个与类名称相同,无参、无返回值的构造方法
public Employee(){
}
对上面提到的(3)可以看以下范例:
class Employee {
private String name;
private int age;
private double salary;
public Employee(){
System.out.println("这是一个无参的构造方法");
}
}
public class Demo3{
public static void main(String[]args){
Employee person1=null;
}
}
结果:
并没有打印出东西。接下来加入实例化代码
public class Demo3{
public static void main(String[]args){
Employee person1=null;//声明对象
person1 = new Employee();//实例化对象
}
}
结果:
结论:关键字new分配内存空间实例化对象时构造方法才被调用。
思考:构造方法没有返回值,为什么没有void声明?
==>1、属性是在对象开辟堆内存时开辟的空间
2、构造方法是在new后调用的(只调用一次)
3、普通方法是在空间开辟了,构造方法执行之后多次调用的
public void Emplayee() {} //命名不标准的普通方法
public Emplayee() {} //无参构造方法
==>因此编译器是根据程序结构来区分普通方法和构造方法的,所以在构造方法前,没有返回值声明。
建议:在定义时:①定义属性==>②定义构造方法==>③定义普通方法
在实际开发中,构造方法的作用是在类对象实例化的时候设置属性的初始化内容:
class Employee {
private String name;
private int age;
private double salary;
public Employee(String name,int age,double salary){
this.name=name;
this.age=age;
this.salary=salary;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age=age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public void get() {
System.out.println("名字" + name + "年龄" + age + "薪资" + salary);
}
}
public class Demo3{
public static void main(String[]args){
Employee person1=null;//声明对象
person1 = new Employee("king",28,100000);//实例化对象
person1.get();
}
}
结果:
构造方法重载
构造方法也属于方法,所以构造方法也可以重载
重载:函数名相同,参数列表不同,返回值不做要求
范例:
class Employee {
private String name;
private int age;
private double salary;
public Employee() {
System.out.println("这是一个无参的构造方法");
}
public Employee(String name){
this.name=name;
System.out.println("这是有一个参数的构造方法");
}
public Employee(String name,int age,double salary){
this.name=name;
this.age=age;
this.salary=salary;
System.out.println("这是有三个参数的构造方法");
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age=age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public void get() {
System.out.println("名字" + name + "年龄" + age + "薪资" + salary);
}
}
public class Demo3{
public static void main(String[]args){
Employee person1=new Employee();
person1.get();
Employee person2=new Employee("king");
person2.get();
Employee person3=new Employee("king",28,10000);
person3.get();
}
}
结果:
构造方法重载时建议:按照参数个数升序或降序
如果类中的属性直接设置默认值
private String name="queen";
private int age=18;
private double salary=20000;
结果:
结论: (1)在类中直接设置属性默认值(2)这个默认值是在构造方法执行后设置的(3)属性内容为对应数据类型默认值时,属性才会设置类中定义的默认值;但是在构造方法没有执行之前,属性内容都是其对应的数据类型的默认值。
三、匿名对象
new Employee("这是个托",18,2000).get();
没有名称的对象称为匿名对象,对象的名称(保存的堆内存的地址),在上篇提过其内存关系,如下图:
匿名对象没有对象名称,也就是没有栈内存指向堆内存,所以匿名对象使用一次后就称为垃圾空间。
范例:
class Employee {
private String name;
private int age;
private double salary;
public Employee(String name,int age,double salary){
this.name=name;
this.age=age;
this.salary=salary;
System.out.println("这是有三个参数的构造方法");
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age=age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public void get() {
System.out.println("名字:" + name + "年龄:" + age + "薪资:" + salary);
}
}
public class Demo3{
public static void main(String[]args){
new Employee("这是个托",18,2000).get();
}
}
结果: