目录
4.封装
(学完封装的所有知识点之后,要求能够知道什么是封装以及封装的好处)
4.1private关键字
①是一个权限修饰符
②可以修饰成员(成员变量和成员方法)
③作用是保护乘员不被别的类使用,被private修饰的成员只在本类中才能访问
(也就是一个成员变量被private修饰了,在外界是无法直接访问的,而在本类中是可以直接访问的)
针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作:
- 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
- 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰
(假如变量名是age,使用get方法就写作gatAge(),使用set方法就写作setAge(参数),注意变量名的首字母要大写)
/*
这是一个学生类
*/
public class Student {
//在学生类中又两个成员变量
String name;
//int age;
/*8.为了修改7的问题,我们需要注释掉int age,并修改为private,
这样改了之后在show方法中还是可以使用age的,但是在学生测试类中是不可以使用的
不要慌张,我们知道在针对private修饰的成员变量我们会提供get和set方法,用于设置和获取值来进行修改
*/
private int age;
/*
9.此时上述a.age=30;以及不可用了,我们就要注释掉,
并使用针对private修饰的成员变量我们会提供get和set方法,用于设置和获取值
进行改写. 注意变量的首字母要大写。 那么setAge()方法是用来设置值的,所以
我们需要传递一个值进来 int a,传递之后age就等于a,将来调方法,我带了一个参数,
把这个参数的值赋值给 private int age;中的age
*/
public void setAge(int a) {
//age = a;
//16.注释掉上面age=a;在下面我们来做一个判断
if (a < 0 ||a >120){
System.out.println("你给的年龄有误");
} else{
//17.这个操作也就是说如果a小于0或者大于120,都会提示输入错误,如果输入正确就会赋值给age,然后回到测试类中重新执行
age = a;
}
}
/*10.get类型是要返回一个值的,所以我们返回age,age是int类型的所以返回值类型是int类型的。
到这我们针对这个age这个私有的成员便量,提供了get和set方法,提供完之后回到学生测试类进行修改
*/
public int getAge(){
return age;
}
//在这个类中还有一个成员方法show,这个show方法的作用就是在控制台用来输出name和age的值
public void show(){
System.out.println(name + ";" + age);
}
//然后再去看学生测试类StudentDemo
}
/*
这是一个学生测试类
*/
class StudentDemo {
//1.测试类必须要有main方法
public static void main(String[] args) {
//2.首先在学生测试类main方法里面创建了一个对象
Student s = new Student();
//3.接着通过这个对象给成员变量赋值,成员变量赋值前面必须带上对象.
s.name = "林青霞";
//s.age = 30;
//6.修改age的值为-30,并注释掉age=30;
//11.回来之后我们要把a.age = -30;注释掉
//s.age = -30;
//12.这一次我们采用方法来设置成员变量的值,我们先给个30的值
//s.setAge(30);//13. 这一次的运行结果是 林青霞,30
//14.我们注释掉s.setAge(30);把成员变量值修改为-30
//s.setAge(-30);//得到 林青霞,-30
/*15.那么我们做了这么多操作,怎么还是一样的?
目前来说,它现在是一样的 但是,我在方法中我是可以对参数a进行判断的
现在回到方法中
*/
/*18.现在重新执行s.setAge(-30);得到的结果就是提示语:你输入的年龄有误,和林青霞,0
这个0是怎么来的呢,因为我们设置的值失败,也就是第17步操作没有给age赋上值
但是这个age是个成员变量,他是有默认值的所以这里的0是它的默认值
*/
//19.然后我们把s.setAge(-30);注释掉,并重新改写年龄为18
s.setAge(18);//执行得到林青霞,18,这次就不会得到提示信息,直接把正确的值赋值成功
//4.最后通过这个对象调用了show方法
s.show();
/*5.而show方法的作用是在控制台输出name和age两个成员变量的值
所以这一次得到的值是 林青霞,30
7.这次输出的值为 林青霞,-30
但是age代表的是年龄,年龄怎么可能是负数。
我们就要不让外界直接访问这个成员变量的值。怎么做呢?
*/
}
}
4.2private关键字的使用
一个标准类的编写:
- 把成员变量用private修饰
- 提供对应的getXxx()/setXxx()方法
代码演示:
/*
学生类
*/
public class Student1 {
//先使用private修饰成员变量
private String name;
private int age;
//使用get/set方法
public void setName(String n ){
name = n;
}
public String getName() {
return name;
}
public void setAge(int a){
//此处可以做判断,只是现在不需要做判断
age = a;
}
public int getAge(){
return age;
}
//再给一个show方法
public void show(){
System.out.println(name + "," + age);
}
}
/*
学生测试类
*/
class StudentDemo1 {
//测试类需要用到main方法
public static void main(String[] args) {
//创建需要测试的对象
Student1 s = new Student1();
//需要使用set方法给给成员变量赋值
s.setName("林青霞");
s.setAge(18);
//调用show方法
s.show();//这里就会得到 林青霞,18
//比如show方法使用的是逗号, 进行拼接的,我想把它换成----怎么办呢
System.out.println(s.getName() + "----" + s.getAge());//这里会得到 林青霞----18
}
}
4.3this关键字
首先代码演示:
/*
学生类
*/
public class Student2 {
//使用private修饰成员变量
private String name;
private int age;
//对应的就给出了get/set方法
/*
这里的n是要赋值给name的,也就是n代表的是name的意思
而n代表不了姓名,所以n这个名字起得不好,我们把它注释掉
*/
// public void setName(String n){
// name = n;
// }
//改好之后name就就叫name了就不叫n了。
public void setName(String name){
//我要把setName方法的形参name赋值给成员变量name就需要这样写
//name = name;这样写是不行的,因为这是局部变量
//name = name;//这里只会得到null(这个name没有用this修饰所以就是局部变量)
//用this修饰的变量就指代的是成员变量,
this.name = name;
}
public String getName(){
return name;
}
//看了上面的描述改写下列代码
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
//定义一个show方法
public void show(){
//show方法用于在控制台输出成员变量的值
System.out.println(name + "," + age);
}
}
/*
学生测试类
*/
class StudentDemo2 {
public static void main(String[] args) {
//创建对象
Student2 s = new Student2();
//给成员变量赋值
s.setName("林青霞");
s.setAge(18);
//调用show方法
s.show();
}
}
总结:
- this修饰的变量用于指代成员变量
方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
getName方法在这个方法里的括号没有写形参名字,就默认叫name,所以直接在方法中写name,虽然他没有用this修饰,但是它直接代表的是成员变量
- 上面时候使用this呢?
就是在局部变量跟成员变量同名的时候,为了怕这个局部变量把成员变量隐藏了所以我们加this修饰,
这个操作叫解决局部变量隐藏成员变量。
- this:代表所在类的对象引用
记住:方法被那个对象调用,this就代表哪个对象
看这里,在这个main方法中我们创建了两个对象,先说第一个对象s1调用setName方法,那这个时候在setName方法里面的this代表的就是s1这个对象。
我们再来看s2这个对象,这个时候在setNmae方法里面this就代表的是s2.
4.4this内存原理
我们先来看这段代码,这里创建了两个对象,这两个对象分别调用了setName方法,现在来说一下他在内存中的执行流程:
程序执行从main方法开始,首先main方法进入栈内存,
然后在执行Student s1 = new Student();代码
创建了第一个对象s1,
然后右边的内容在堆内存new了一个空间(假设地址值是001)然后Student中有两个成员变量就会把这两个放置在堆内存中,现在并未对这两个成员变量name和age赋值,所以他们的值为默认值null和0;然后把001的地址值赋值给了s1,
然后调用方法然后setName方法就会进入栈内存,进入栈内存之后setName方法有个形参name,name的值是我们传递过来的(“林青霞”);然后这个方法是被对象s1调用的,所以这个方法的调用者是s1,s1的地址值是001。
这个时候在setName方法中他有一个this,这个this就是s1。
然后进入到方法中执行this.name = name;
因为this就是s1,所以this通过001指向堆内存中的001这块地址,然后name就找到了001这块地址的name,然后将参数“林青霞”赋值给name(修改name的值为“林青霞”)
这个做完之后,setName方法调用完毕,然后setName方法从栈内存中消失
再接着,开始创建第二个对象s2,new Student在堆内存new了一个新的空间(假设地址值为002),并将Student的成员变量放置在这个空间内,它也会有一个默认值,并将002的值赋值给对象s2。
然后往下执行,s2.setName(“张曼玉”);
调用方法,setName方法首先加载到栈内存中,这次这个参数的值是“张曼玉”,调用者是s2,这次的this是s2,
然后this通过002指向堆内存002这块内存空间,通过name找到002这块内存空间里的name并把参数“张曼玉”传递过去,并修改对应的值为“张曼玉“。
修改完之后setNmen方法就执行完毕,并冲栈内存消失
再往下走,main方法指向完毕,并从扎内存消失。
总结:最后重点说一下,方法被哪个对象调用,哪个方法里面的this就代表的是哪个对象
4.5封装
1.封装概述:
封装是面向对象三大特征之一(封装,继承,多态)
封装是面向对象编程语言对客观世界的模拟,客观世界里成员变量都生隐藏在对象内部的,外界是无法直接操作的。
2.封装原则:
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
比如说成员变量private,提供对应的getXxx()/setXxx()方法。
例如这个学生类中有两个成员变量,name和age他们都使用了private修饰,如果外界要访问这两个变量,就必须使用我们提供的公共的get和set方法来访问:
3.封装的好处:
通过方法来控制成员变量的操作,提高了代码的安全性
(因为在方法中是可以对数据进行数据安全效验的)
把代码用方法进行封装,提高了代码的复用性。
(因为方法中可能有很多行代码,如果每次使用都去编写这么多行的代码就太麻烦了,我们用一个方法来封装,这样我们每次使用的时候,只需要调用这个方法即可,这样就提高了代码的复用性)