今天我们来聊一聊访问控制
什么是访问控制呢?
访问控制就是JAVA中控制类外的程序,能够访问类中的那些的成员。
有些人可能会问了,类的成员变量不是都能在外部访问吗? 其实不是的。
这和现实中一样。我们有很多属性也是不能对外公开的,比如说你的银行卡的卡号和密码,或者说银行存折的余额,女孩的体重,女孩的年龄这些都是不能被访问的。
JAVA中也是一样的,我们的类中的成员不应该被随便就被外界轻易的访问到,甚至被外界破坏掉。
JAVA中使用类封装成员,并不是仅仅为了,把成员集中在一起保存这么简单,它更重要的目的是保护这些成员。
JAVA的4个保护级别
第一种是 pubulic , public级别是最公开的,也就是完全没有限制可以随便的访问
第二种是 private ,它和public相反,它是私有的,也就是完全的私密,外界完全不能访问
第三种是 protected,它是专门用于继承当中的父子类之间
第四种就是默认的控制级别
访问控制
在讲访问控制之前,我们先讲一下包,那么什么是包呢?
包(package)
・在硬盘.上,包是存储多类(.class)的文件夹
・在程序中,组织多类名,避免类名冲突的名称空间
・包的作用,就是分组管理类定义,并避免类名冲突
・Java源代码中,第一行, 一般都要指定当前类所属的包名,
・语法:
・package 包名; 其中 ,包名建议所有字母小写。
・其实, Java中一个类的全名,应该是:包名.类名。
-例如:
・Java规定:
-任何类的.class文件,必须保存在类中指定的包名文件夹下。
-同一个包中不能保存两个同名的类
package语句
包名也可以有层次结构。定义多层包名,语法:
- package 顶级包名.子级包名…n级包名;
-说明,每一级包名使用 “.” 连接。
-包名层次结构和文件夹层次结构完全对应
多层包名的一般规范: package 公司或组织的域名.项目名.功能模块名
例如:
org.apache.commons.lang
org.apache 公司域名
commons 项目名称
lang 功能模块
再比如:腾讯公司要做一套学生管理系统。 其中包含一个课程管理功能模块:
com.tencent .studentmgt .coursemgt
import语句
・访问类时都需要使用类的全称。如果不写全称,仅用类名,默认只在当前包中寻找。
例如: Scanner类,其实全称: java.util.Scanner
java.util.Scanner sc=new java.util.Scanner(System.in);
//编译正确。但是太繁琐
可以通过import语句先引入类的全称,语法:
- import类的完全限定名;
-完全限定名:就是包名.类名
通过import语句引入了类的全称后,在当前源文件中就可以仅使用类名访问了
例如:
import java util. Scanner;
Scanner sc=new Scanner(System.in);
//编译正确。因为已经导入了完全限定的类名
接下来我们直入主题 学习访问控制修饰符
访问控制修饰符
封装的意义
水果店的功能,无非就是上货,打包,称重,收款等等
现在水果店有2种经营模式:
A:老板当甩手掌柜,客户自己随便取水果、随便称重,随便找零钱。
B:老板帮客户取水果,打包,找零。
第一种经营模式肯定行不通,可能上午开门,下午就倒闭了。
封装的意义
对外提供可调用的、 稳定的功能;
封装内部具体的实现细节, 外界不可访问,这样的好处在于:
-降低出错的可能性,便于维护;
-内部变化,不会影响外部使用;
public和private
●private修饰的成员只能在本类的成员方法中使用
●通常类的成员变量都应该使用private严格控制。只能通过类提供的方法访问。
●private修饰的成员仅是对内使用,如果“公开”会大幅增加维护成本。
●public修饰的成员可以在任何地方使用。
●凡是对外的成员方法要非常的健壮和稳定
封装水果店属性和功能的类
package day07;
/**
* 封装水果店属性和功能的类
*/
public class Shop {
double buying=5.5; //水果的进价5块5一斤
double price=8; //销量8块一斤
double total; //销售量(斤数)
/**
* 卖水果的方法
* money 多少钱
* count 多少斤
*/
void sale(double money,double count){
//累加销量量
total+=count;
//输出本次购买的结果
System.out.println("您购买的水果"+count
+"斤水果,收您"+money
+"元,找零"+(money-price*count));
}
}
我们先来测试:如果一个顾客进到店里买水果,他先看了看进价,又看了看售价,感觉卖的太贵了,一气之下把你的售价改成了0.01元,然后给了一百元。
package day07;
public class Test {
public static void main(String[] args) {
Shop s=new Shop();
//加入一个顾客来买水果,先看了进价5.5元
System.out.println(s.buying);
//又看了看售价8元
System.out.println(s.price);
//他愤怒的把售价price改成为0.01
s.price=0.01;
//再调用sale方法
s.sale(100,10);
}
}
以上案例可以知道,我们的进价是不能让人轻易的看见或修改,那么怎么解决这个问题呢?
我们来对代码进行修改,让进价不可见,让售价不能修改,也要加上private!
package day07;
/**
* 封装水果店属性和功能的类
*/
public class Shop {
private double buying=5.5; //水果的进价5块5一斤
private double price=8; //销量8块一斤
double total; //销售量(斤数)
/**
*专门读取price属性的方法
* 相当于老板可以告诉客人,这水果多少钱,但是客人不知道
* @return
*/
public double getBuying() {
return buying;
}
public double getPrice() {
return price;
}
/**
* 卖水果的方法
* money 多少钱
* count 多少斤
*/
void sale(double money,double count){
//累加销量量
total+=count;
//输出本次购买的结果
System.out.println("您购买的水果"+count
+"斤水果,收您"+money
+"元,找零"+(money-price*count));
}
}
经过修改private 加密,我们可以发现无法进行读取和修改了
只能通过get方法调用
package day07;
public class Test {
public static void main(String[] args) {
Shop s=new Shop();
//加入一个顾客来买水果,先看了进价5.5元
//System.out.println(s.buying);
System.out.println(s.getBuying());
//又看了看售价8元
//System.out.println(s.price);
System.out.println(s.getPrice());
//他愤怒的把售价price改成为0.01
// s.price=0.01; 已经无法修改
//再调用sale方法
s.sale(100,10);
}
}
但是上面的代码还是不够完善,比如用户输入购买金额小于0怎么办,在比如用户金额小于应付金额怎么办?
接下来我们就继续修改,完善此代码:
package day07;
/**
* 封装水果店属性和功能的类
*/
public class Shop {
private double buying=5.5; //水果的进价5块5一斤
private double price=8; //销量8块一斤
double total; //销售量(斤数)
/**
*专门读取price属性的方法
* 相当于老板可以告诉客人,这水果多少钱,但是客人不知道
* @return
*/
public double getBuying() {
return buying;
}
public double getPrice() {
return price;
}
/**
* 卖水果的方法
* money 多少钱
* count 多少斤
*/
void sale(double money,double count){
/*公开的方法,要放出错*/
if (money< 0 || count <=0){ //数量<=0
System.out.println("购买的数量和钱必须>0");
}else if (money<price*count){ //钱给的不够
System.out.println("你的钱不够");
}else{//正常执行逻辑
//累加销量量
total+=count;
//输出本次购买的结果
System.out.println("您购买的水果"+count
+"斤水果,收您"+money
+"元,找零"+(money-price*count));
}
}
}
根据修改,我们可以发现,现在代码逻辑执行正常了
package day07;
public class Test {
public static void main(String[] args) {
Shop s=new Shop();
//加入一个顾客来买水果,先看了进价5.5元
//System.out.println(s.buying);
System.out.println(s.getBuying());
//又看了看售价8元
//System.out.println(s.price);
System.out.println(s.getPrice());
//他愤怒的把售价price改成为0.01
// s.price=0.01; 已经无法修改
//再调用sale方法
s.sale(50,10); //付款50元,应付款80元,钱不够
s.sale(-10,10);//付款-10元,购买的数量和钱必须>0
}
}
protected和默认访问控制
●默认访问控制(不写任何修饰符)的成员,仅在同一个包中可用
●protected修饰的成员可以被同一个包中的类以及子类使用。
生活案例:包就好像我们现实中,我们家的小区,Shop类就好像我们小区内的一个水果店,默认只有本小区的人才知道,其他小区的人是不知道的。
public void sale(double money,double count){
如果我们想其他小区的人,也知道本小区有水果店呢? 现实中一般老板会在小区门口放一个大大的广告牌,public就正好相当于这个广告牌,路过的人,都能看见,都能调用。
如果我们想其他小区的人,也知道本小区有水果店呢? 现实中一般老板会在小区门口放一个大大的广告牌,public就正好相当于这个广告牌,路过的人,都能看见,都能调用。
package day07;
/**
* 封装水果店属性和功能的类
*/
public class Shop {
private double buying=5.5; //水果的进价5块5一斤
private double price=8; //销量8块一斤
double total; //销售量(斤数)
/**
*专门读取price属性的方法
* 相当于老板可以告诉客人,这水果多少钱,但是客人不知道
* @return
*/
public double getBuying() {
return buying;
}
public double getPrice() {
return price;
}
/**
* 卖水果的方法
* money 多少钱
* count 多少斤
*/
public void sale(double money,double count){
/*公开的方法,要放出错*/
if (money< 0 || count <=0){ //数量<=0
System.out.println("购买的数量和钱必须>0");
}else if (money<price*count){ //钱给的不够
System.out.println("你的钱不够");
}else{//正常执行逻辑
//累加销量量
total+=count;
//输出本次购买的结果
System.out.println("您购买的水果"+count
+"斤水果,收您"+money
+"元,找零"+(money-price*count));
}
}
}
新建一个包,创建一个新的Test
package day08;
import day07.Shop;//导入day7中的Shop类
public class Test {
public static void main(String[] args) {
Shop s = new Shop();
s.sale(100,10);
}
}
我们可以发现,给方法加上public过后,隔壁小区的也能购买了
这时,我们在隔壁小区开一家分店,属性和方法,都和总店一样。
package day07;
/**
* 封装水果店属性和功能的类
*/
public class Shop {
private double buying=5.5; //水果的进价5块5一斤
private double price=8; //销量8块一斤
double total; //销售量(斤数)
/**
*专门读取price属性的方法
* 相当于老板可以告诉客人,这水果多少钱,但是客人不知道
* @return
*/
public double getBuying() {
return buying;
}
public double getPrice() {
return price;
}
/**
* 卖水果的方法
* money 多少钱
* count 多少斤
*/
protected void sale(double money,double count){
/*公开的方法,要放出错*/
if (money< 0 || count <=0){ //数量<=0
System.out.println("购买的数量和钱必须>0");
}else if (money<price*count){ //钱给的不够
System.out.println("你的钱不够");
}else{//正常执行逻辑
//累加销量量
total+=count;
//输出本次购买的结果
System.out.println("您购买的水果"+count
+"斤水果,收您"+money
+"元,找零"+(money-price*count));
}
}
}
开一家分店
package day08;
import day07.Shop;
/**
* 开了一个分店
*/
public class SubShop extends Shop {
/**
* 重写父类的sale方法,使用super调用父类的sale方法
* JAVA中规定,子类重写父类的方法,子类中的方法访问控制范围不能小于父类方法的控制范围
*/
protected void sale(double money,double count){
super.sale(money,count);
}
}
测试:
package day08;
public class Test {
public static void main(String[] args) {
SubShop ss= new SubShop();
ss.sale(100,10);//100块,10斤
}
}
访问控制符修饰成员
访问控制符修饰成员时的访问权限如下表所示:
●对于类的修饰可以使用public和默认方式。public修饰的类可以被任何一 个类使用;默认访问控制的类只可以被同一个包中的类使用。