不知道大家在平时的开发过程中有没有注意到访问修饰符,哈哈哈,有没有懵,在java中有哪些访问修饰符,还记得清吗?今天想分享下访问修饰符的哪些小事。
一、访问修饰符有哪些
在java中提到访问修饰符,大家可能都不陌生,但对于访问修饰符我还是想再重申下,这些看似很普通的概念,在多年后的某个瞬间总能激起我们某些想法。
java中说白了就三种元素:类、方法、属性,由这三种元素组合成了我们平时使用的API,来标识这三种元素的访问权限的字符就是访问修饰符,通俗点理解就是我有一个方法我只想自己自己知道,我不想别人知道那么我给它一个标识private,代表是私有的,那么别人就无法访问了,如果我想让方圆5公里的人知道,我给它个标识protected,那么就只有方圆5公里的人知道。访问修饰符就是来控制类、方法、属性的访问范围的。
在java中有四种访问修饰符,分别是public、protected、default、private。上面说到java中有类、方法、属性,下面看下这几种访问修饰符怎么起作用的。
先上一张图,让大家有个大体的印象,
1.1、public
public,公开的,公共的。可以修饰类、方法、属性。在修饰类的时候,一个.java文件中只能有一个类是公共的,且和.java文件同名;重点看下最后这句话,
看到了吧,在idea中给的提示很明确,Teacher是公共的(public),应该声明到一个文件名为Teacher.java的文件中。其实也很容易理解,在一个.java文件中有多个公共的class,是无法区分哪个是主类的,所以在一个.java文件中只能有一个公共的类。遗留一个小问题,在一个public的类中可以有其他修饰符修饰的类吗?后面揭晓。
public修饰方法和属性,想必不用我多说了,在平时使用的比较多,public修饰方法和属性不受包的限制,在任何包中均可访问。
1.2、protected
protected,受保护的。可以修饰内部类、方法、属性。这里有个概念是内部类,当然和内部类相对应的就是外部类,所谓内部类就是在一个外部类中的类,外部类就是平时我们写的类,其类名和文件名一样。一个例子如下,
package com.example.day04;
/**
Teacher是外部类
*/
public class Teacher {
/**
* Inner是内部类
*/
protected class Inner{
}
}
重点来看下protected修饰的方法和属性,
package com.example.day04;
/**
Teacher是外部类
*/
public class Teacher {
protected String name;
protected void method(){
System.out.println(this.name);
}
}
那么name和method()方法可以被哪些类访问呐?看下本包中的类,
package com.example.day04;
public class TeacherA {
public static void main(String[] args) {
Teacher teacher=new Teacher();
teacher.name="tom";
teacher.method();
}
}
protected修饰的方法、属性可以被本包中的类访问,再来看下本包中的子类,
package com.example.day04;
public class TeacherB extends Teacher{
public static void main(String[] args) {
TeacherB teacherB=new TeacherB();
teacherB.name="tom";
teacherB.method();
}
}
打印结果如下,
tom
Process finished with exit code 0
protected修饰的方法、属性可以被本包中的子类访问,再来看下不同包中的类,
protected修饰的方法、属性不可以被不同包中的类访问,那么不同包的子类呐?
package cn.example.day04;
import com.example.day04.Teacher;
public class TeacherD extends Teacher {
public static void main(String[] args) {
TeacherD teacherD=new TeacherD();
teacherD.name="tome";
teacherD.method();
}
}
结果如下,
tome
Process finished with exit code 0
protected修饰的方法、属性可以被不同包中的子类访问。
总结:protected修饰的属性和方法可以被同包中的类、子类访问;可以被不同包的子类访问,不可以被不同包的类访问。
1.3、default
这里说default其实不是那么严格,在java中不写访问修饰符,就是default,称为default只为了好记,其实没有“default”这个访问修饰符。
default,默认的访问修饰符。可以用来修饰类、属性、方法。
有default修饰的类、属性、方法,
package com.example.day04;
class Address {
String name;
void method(){
System.out.println(name);
}
}
在本包下的类,
package com.example.day04;
public class AddressA {
public static void main(String[] args) {
Address address=new Address();
address.name="china";
address.method();
}
}
结果如下,
china
Process finished with exit code 0
默认情况下的访问修饰符,在本包下的类是可以访问的。看下在本包下的子类,
package com.example.day04;
public class AddressB extends Address{
public static void main(String[] args) {
Address address=new Address();
address.name="china";
address.method();
}
}
看代码正常编译未出错,肯定是可以的。
默认情况下的访问修饰符,在本包下的子类是可以访问的。不同包下的类和子类,这里不再一一列出例子了,直接给出下面的结论,
默认情况下的访问修饰符,在不同包下的类、子类都是不可以访问的默认修饰符修饰的类、属性、方法。
总结,默认情况下的访问修饰符,在本包下的类、子类是可以访问的;在不同包下的类、子类都是不可以访问
1.4、private
private,私有的。可以修饰类、属性、方法。
在private修饰类时,不可以修饰外部类,可以修饰内部类。重点看下修饰的属性、方法,这个是我们在平时开发中用的最多的。
这里有一个使用private修饰的属性、方法,
package com.example.day04;
public class Person {
private String name;
private void method(){
System.out.println(name);
}
private class A{
}
}
看下图,在本包中,
private修饰的属性、方法在本包中的类中是无法访问的。看下在本包的子类呐?
private修饰的属性、方法在本包的子类中是无法访问的。
总结,private修饰的属性、方法在本包中的类、子类是无法访问的,在不同包的类、子类是无法访问的。
二、一些小趣事
上面说了很多乏味的基础知识,在日常的开发中你可能都意识不到天天在用。下面看一下几个有意思的小问题。
2.1、一个public修饰的类中可以有其他类吗
我们知道一个public修饰的类的类名和.java文件名是一样的,那么在这个类中还可以有其他类吗?
从上图中可以看到,一个public修饰的类中仅可以有默认修饰符修饰的类,protected、private修饰的均不可以,public修饰的也不可以哦。
2.2、protected方法存在的意义
protected修饰的方法可以在本包类、子类、不同包的子类访问。这种方法存在的意义是什么呐?在继承中,子类可以访问父类的protected方法,既然是继承了,那么没继承的类便不可访问,protected很好的诠释了继承的意义。平时开发中使用protected方法是在抽象类中的抽象方法。
package com.example.day04;
/**
* 抽象的Car工厂
*/
public abstract class AbstractCarFactory {
protected abstract void generateCar();
}
那么子类需要去覆盖该抽象方法,非子类不需要覆盖该方法,所以这个方法是protected访问修饰符修饰的。有人会说是public修饰的可以吗?当然可以,但是权限肯定是越小越好啊,
package com.example.day04;
public class BiyadiCarFactroy extends AbstractCarFactory{
@Override
public void generateCar() {
System.out.println("generate biyadi car");
}
}
在子类中还可以改变覆盖方法的访问修饰符。
2.3、有了private为什么还要public
在开发中写的最多的可能就是类似下面的实体类,
package com.example.day04;
public class Address {
private String name;
private String code;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
Address类中属性是private,而getXXX和setXXX方法是public,这是为了保护属性,方式使用实例.属性的方式进行设置/获取值,而是通过其提供的setXXX/getXXX方法来设置/获取值。通过方法的方式,可以在设置值的过程中对值进行校验、判断等操作,而直接通过实例.属性的方式则无法完成上面的操作,只不过在日常的开发中,都是直接赋值,没有进行校验、判断等其他操作而已。例下方,
public void setName(String name) {
System.out.println("设置name的值为:"+name);
if(name.equals("china")){
this.name = name;
}
System.out.println("设置完成");
}
2.4、子类无法访问父类的私有属性吗
上面我们知道在子类中是无法访问父类的私有属性的,因为属性是私有的即使子类也是无法访问的。但我依然可以访问到,
我们直接无法访问到name属性,但是我们可以通过其暴露的getXXX方法啊。
三、总结
本文分享了在平时开发中很容易忽略的一个点,就是访问修饰符,我们平时用的最多的要属public、private,但是为什么要使用,这样使用的好处是什么。有人说一个项目中都是自己项目内的人,没必要考虑访问修饰符,我直接都用public不是更好,这样也没错,但是这样带来的后果是没有任何的访问限制,类比生活中人人都是想怎么干就怎么干,想去什么地方就去什么地方,这样岂不是没了规则,这个社会是不是无法正常运转了。到了程序中虽然没有那么严重,但是遵循一定的原则,对代码的整体设计后续的扩展性也是好的。本文只是想做个引子,提醒小伙伴们日常的开发中多思考,多尝试。