访问修饰符 [详解]

article/2025/9/9 21:43:40

可能一下子会想到private、default、protected、public这四个,但如果问"static、abstract等是不是访问修饰符呢?"

这就不清楚了,所以下面研究前四个再补充其他的

1、当前已知的

过一眼就行,毕竟后面会重新研究

1.1

范围从大到小排序是:public>protected>默认>private

1.2、修饰符列表包含权限修饰符和修饰符

private、default、protected、public又都可叫权限修饰符

而 static、final、abstract这些是修饰符

权限修饰符和修饰符概念不同

再讲一个词’修饰符列表’。修饰符列表在方法的定义那里说过

修饰符列表 返回值类型 方法名(参数列表){方法体}

我认为修饰符列表包含权限修饰符修饰符

注1:子类在别的包下,那可以拿到protected修饰的吗?

        可以,所以前面1.1中"子类"应该更正。protected的范围允许的"子类"完善、准确说是也可以是不同包的子类,即"被protected修饰的可以被本类、同包类、(可以是不同包中的)子类所访问到"

注2:如果子类在同一包下,那默认也能拿,跟是不是子类没关系?

        是的。提问的意思是:子类处于同一包下,而权限修饰符使用的是defalut,那么子类可以访问到default修饰的是因为"default允许访问本类、同包类",子类算在同包类的范围了

2、查阅可知

开始重新研究

2.1、首先查阅《java语言程序设计》

1、前面所说的"权限修饰符",这里是叫做可见性修饰符

2、可见性修饰符针对的是类及类的成员。这里将修饰的范围定在了类和类的成员,实际修饰范围可以讲得更具体,比如分属性、方法、内部类啥的,但是目前没必要。所以仅仅知道"修饰的范围分类和类的成员"即可,具体如"public和default可以修饰类及类的成员,而private和protected只可以修饰类的成员"

3、default修饰的可以被称为"包私有"和"包内访问",注意这里的英文单词package-private,不要看到private就认为是在说"private修饰啥啥的"

4、注意图9-15的C1类是default修饰的,而C2类、C3类都是public修饰的。所以C3类可以访问C2类是因为public修饰允许任意类访问 

5、图9-16后面的那句话很重要。看左边代码,由于对象、私有的属性、方法都是在同一类中的,所以对象可以访问该类的私有属性、方法。再看我说的很重要的那句话,现在看是废话,但是再看右边代码,正是因为属性、方法都是私有的,所以本类中有效,而对象声明在了其他类中,所以这时候对象就不能访问私有属性、方法了。这一点后面再讲protected时还会再重申,毕竟"private修饰的是本类私有、只在本类有效"都知道,但是看到右边代码明明声明了对象,按理说对象点私有属性、方法应该可以吧,实际是不行。所以图9-16后面的那句话要记记

6、这里讲"只允许子类去访问父类的属性、方法,所以用protected来修饰父类"其实涉及到一个知识点:就是可见性修饰符不是乱选的,是限定在合适的范围内最好。这合适的范围好确定吗?其实上面第二段不就是提出需求"只允许子类去访问父类的属性、方法",然后选择采用protected来修饰父类

7、初学时,常看见public修饰、default修饰;再知道封装、继承啥的知道"private封装私有属性+会编写setter()、getter()"可以实现"封装简单逻辑、暴露实际访问"、再知道还有protected这个修饰符。想说的是:1、摒弃"什么都用public修饰蛮好的"思路;2、学会根据需求用可见性修饰符控制合适的范围内可见

 上面归纳出的七点内容,可以再整理为下面几点

1、"权限修饰符"也可叫做"可见性修饰符"、"可访问性修饰符"

2、当前知道可见性修饰符针对的范围是"类"及"类的成员"就够了。具体点是:public和default可以修饰类及类的成员,而private和protected只可以修饰类的成员。可以在具体点讲范围包括内部类、属性、方法啥的,但是目前真没必要

3、default修饰的可以被成为"包私有"和"包内访问",注意这里的英文单词package-private,不要看到private就认为是在说"private修饰啥啥的"

4、是前面的第五点,还不能总结出一个很好的说法。大致是:A类访问B类的成员,如果是A类去访问B类的成员,那么A类要能够访问B类,也就是"访问对象"A类的权限起码的是同B类的。如果是A类中声明的对象去访问B类的成员,则这个声明的对象应该可以访问B类。说的不是很好,还是借助前面第五点用的例子再理解吧

5、可见性修饰符不是乱选的,是限定在合适的范围内最好。根据访问需求来选择可见性修饰符

6、其实是对5的补充:1、摒弃"什么都用public修饰蛮好的"思路;2、学会根据需求用可见性修饰符控制合适的范围内可见

7、觉得前面总结的还是复杂,就先记住下面两点:1是记住private、default、protected、public的那张可见性限制范围的表;2是记住public和default可以修饰类及类的成员,而private和protected只能修饰类的成员

下面会说private和protected是可以修饰内部类的。和上面矛盾吗?其实不算矛盾,是前面没讲的很细罢了

2.2、再查

        在java语言中提供了多个作用域修饰符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile。这些修饰符有类修饰符、变量修饰符和方法修饰符。下面将详细介绍访问控制修饰符->所以前面说到的四个可见性修饰符在这里又叫做"访问控制修饰符"。另外final、abstract这些这一节不介绍

        访问控制符是一组限定类、属性或方法是否可以被程序里的其他部分访问和调用的修饰符。类的访问控制符只能是空或者 public(对应上面说的"private和protected只能修饰类的成员,public和protected可以修饰类和类的成员"),方法和属性的访问控制符有 4 个,分别是 public、 private、protected 和 friendly。其中 friendly 是一种没有定义专门的访问控制符的默认情况

访问控制修饰符的权限如下表 1 所示->这里的说法,"默认"用词是friendly而不是default。其实差别不大

表1 各种访问修饰符的可访问性
访问范围privatefriendly(默认)protectedpublic
同一个类可访问可访问可访问可访问
同一包中的其他类不可访问可访问可访问可访问
不同包中的子类不可访问不可访问可访问可访问
不同包中的非子类不可访问不可访问不可访问可访问

可见friendly除了名和default不同外,效果一致

访问控制在面向对象技术中处于很重要的地位。合理地使用访问控制符可以通过降低类和类之间的耦合性(关联性)来降低整个项目的复杂度,也便于整个项目的开发和维护

在 Java 语言中,访问控制修饰符有 4 种

1. private

        用 private 修饰的类成员只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此private 修饰符具有最高的保护级别。例如设 PhoneCard 是电话卡类,电话卡都有密码,因此该类有一个密码域,可以把该类的密码域声明为私有成员

2. friendly(默认)

        如果一个类没有访问控制符,说明它具有默认的访问控制特性。这种默认的访问控制权规定:该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类。(如果这个子类也是同包的,则可以访问)这种访问特性又称为包访问性package private->前面说"默认修饰则子类在同包也是按照同包算的",这里就是依据

        同样,类内的成员如果没有访问控制符,也说明它们具有包访问性,或称为友元friend)。定义在同一个文件夹中的所有类属于一个包,所以前面的程序要把用户自定义的类放在同一个文件夹中(Java 项目默认的包),以便不加修饰符也能运行

3. protected

        用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类。使用 protected 修饰符的主要作用是允许其他包中它的子类来访问父类的特定属性和方法,否则可以使用默认访问控制符->"主要"一词感觉特别重要

4. public

        当一个类被声明为 public 时,它就具有了被其他包中的类访问的可能性。只要包中的其他类在程序中使用 import 语句引入 public 类 就可以访问和引用这个类

        类中被设定为 public 的方法是这个类对外的接口部分,避免了程序的其他部分直接去操作类内的数据,实际就是数据封装思想的体现。每个 Java 程序的主类都必须是 public 类,也是基于相同的原因

推荐是记忆英文,范围从小到大是private、default或friendly、protected、pubilc,再限制范围是允许本类访问、本类+同包类、本类+同包类+(可以是其它包下的)子类、任意类

2.3、再看

public(公共的)、default(默认的)、protected(受保护的)、private(私有的)

含义

(1)public修饰符,它具有最大的访问权限。可以访问任何一个在CLASSPATH下的类、接口、异常等。它往往用于对外的情况,也就是对象或类对外的一种接口的形式

(2)protected修饰符,它主要的作用就是用来保护子类的。它的含义在于子类可以用它修饰的成员,其他的不可以。它相当于传递给子类的一种继承的东西->再次关注"主要"一词,其实就是想说限制范围的权限修饰符的选择很重要

(3)对于default来说,有点的时候也成为friendly(友员),它是针对本包访问而设计的:任何处于本包下的类、接口、异常等都可以相互访问,即使是父类没有用protected修饰的成员也可以->指出friendly和default是一致的

默认访问修饰是指没有为类、字段、方法等显式声明访问修饰符

(4)private。成员变量和方法都只能在定义它的类中被访问,其他类都访问不到。对成员变量的进行获取和更改,一般用get(),set() ,public 方法。类的权限尽量要小,这样才能减少漏洞和提高安全性,从而体现java面向对象的封装性。访问权限仅限于类的内部,是一种封装的体现。如大多数的成员变量都是修饰符为private的,它们不希望被其他任何外部的类访问

区别

(1)public:可以被所有其他类所访问

(2)private:只能被自己访问和修改

(3)protected:自身,子类及同一个包中类可以访问

(4)default(默认):同一包中的类可以访问,声明时没有加修饰符,认为是friendly

注意:Java的访问控制是停留在编译层的,也就是它不会在.class文件中留下任何的痕迹,只在编译的时候进行访问控制的检查。其实通过反射的手段是可以访问任何包下任何类中的成员。例如访问类的私有成员也是可能的

2.4、

1、类和接口不能声明为:private

2、受保护的访问修饰符不能应用于类和接口;方法,字段可以声明为protected,但是接口中的方法和字段不能声明为protected

3、应用程序的main()方法必须声明为public。否则Java解释器无法调用它来运行该类

4、如果类中存在公共getter方法则可以在类中将变量声明为private。使用private修饰符是对象封装自身并隐藏来自外部世界的数据的主要方式 

通过使用访问控制修饰符来限制对对象私有属性的访问,可以获得 3 个重要的好处

  • 防止对封装数据的未授权访问
  • 有助于保证数据完整性
  • 当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”

5、不能修饰外部类,可以修饰内部类

6、private可以修饰内部类,不可以修饰外部类

5、6两点其实都是针对1.1说"public和default可以修饰类和类的成员,而protected和private只能修饰类的成员"的。不算矛盾,只是1.1范围大概说说而已

2.5、介绍其余的修饰符

具体需要再看2.6

static:修饰变量,称为类变量或静态变量。静态变量是和类存在一起的,每个实例共享这个静态变量,在类加载时初始化

final:被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不能更改。修饰类是不能派生出子类,修饰方法时,不能被当前子类的方法覆盖

abstract:不能创建abstract 类的实例。一般被继承,实现抽象方法。类只要有一个abstract方法,类就必须定义为abstract,但abstract类不一定非要保护abstract方法不可

2.6、 

Java 的修饰符很多,分为访问修饰符非访问修饰符

先看访问修饰符

访问修饰符也叫访问控制符,是指能够控制类、成员变量、方法的使用权限的关键字

在面向对象编程中,访问控制符是一个很重要的概念。可以使用它来保护对类、变量、方法和构造方法的访问

在类中定义访问私有变量的方法,习惯上是这样命名的:在变量名称前面加“get”或“set”,并将变量的首字母大写。例如获取私有变量 name 的方法为 getName()、设置 name 的方法为 setName()。这些方法经常使用,也有了特定的称呼,称为 Getter 和 Setter 方法

如何使用访问控制符

  访问控制符可以让我们很方便的控制代码的权限

  当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为 public

  当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符

  当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为 public、protected 或者省略->就是按需求限定访问范围

继承的规则

  父类中声明为private的方法,不能够被继承

  父类中声明为public的方法在子类中也必须为public

  父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private->其实这块放方法重写那里更好,但下面的这句就不理解了

  父类中默认修饰符声明的方法,能够在子类中声明为private->这个可以?方法重写不是只能重写后的方法访问权限更高吗?

为了实现一些其他的功能,Java 也提供了许多非访问修饰符

static 修饰符,用来修饰类方法和类变量

final 修饰符,用来修饰类、方法和变量。final修饰的类不能够被继承、修饰的方法不能被继承类重新定义、修饰的变量为常量是不可修改的

abstract修饰符,用来创建抽象类和抽象方法

synchronized 和 volatile修饰符,主要用于线程的编程

  • 静态变量

    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。静态变量也被称为类变量。局部变量不能被声明为 static 变量

  • 静态方法

    static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据

对类变量和方法的访问可以直接使用 classname.variablename 和 classname.methodname 的方式访问。如下例所示,static修饰符用来创建类方法和类变量

public class InstanceCounter {private static int numInstances = 0;protected static int getCount() {return numInstances;    }private static void addInstance() {numInstances++;    }InstanceCounter() {InstanceCounter.addInstance();     }public static void main(String[] arguments) {System.out.println("Starting with " + InstanceCounter.getCount() + " instances");for (int i = 0; i < 500; ++i){new InstanceCounter();    }System.out.println("Created " +InstanceCounter.getCount() + " instances");}
}运行结果如下
Starting with 0 instances
Created 500 instances

static修饰类只能修饰内部类,用他修饰后就成了静态内部类。静态内部类可以当做普通类使用而不用先实例化一个外部类

static可以用在修饰类、变量、方法、初始化函数

abstract可以用在修饰类、接口、方法

static全局变量与普通的全局变量:static全局变量只初使化一次,防止在其他文件单元中被引用

static局部变量和普通局部变量:static局部变量只被初始化一次,下一次依据上一次结果值->static不是不能修饰局部变量吗

static函数与普通函数:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

静态变量并不是说其就不能改变值,不能改变值的量叫常量。 其拥有的值是可变的且它会保持最新的值。说其静态是因为它不会随着函数的调用和退出而发生变化。即上次调用函数的时候,如果我们给静态变量赋予某个值的话,下次函数调用时这个值保持不变

再来看final修饰符

首先是final变量,final 变量能被显式地初始化并且只能初始化一次。被声明为 final 的对象的引用不能指向不同的对象,但是 final 对象里的数据可以被改变。也就是说 final 对象的引用不能改变,但是里面的值可以改变。final 修饰符通常和 static 修饰符一起使用来创建类常量 

public class Test{final int value = 10;public static final int BOXWIDTH = 6;static final String TITLE = "Manager";public void changeValue(){value = 12;     将输出一个错误}
}

看上面的changeValue()里面不是不能修改value的值吗?这和介绍的第二句话说"能改变final对象里的数据"矛盾吗?注意是能改是指的final修饰的引用指向的对象不能改,而对象内的值是可以修改的。而这里/演示是赋值基本数据类型,这是必须初始化且只能赋值一次的所以改不了 

再来看final方法

类中的 final 方法可以被子类继承,但是不能被子类修改。声明 final 方法的主要目的是防止该方法的内容被修改。如下所示,使用 final 修饰符声明方法 

public class Test{public final void changeName(){// 方法体}
}

然后看final类

final 类不能被继承,没有类能够继承 final 类的任何特性

public final class Test {// 类体
}

关于final变量,我们还需要知道如下

  • 1、 final 修饰符通常和 static 修饰符一起使用来创建类常量。用final修饰的成员变量表示常量,值一旦给定就无法改变
  • 2、 final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。final变量定义的时候可以先声明而不给初值。这种变量也称为final空白。无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是final空白在final关键字final的使用上提供了更大的灵活性。为此,一个类中的final数据成员就可以实现依对象而有所不同却有保持其恒定不变的特征

  来看下final以及final static修饰的变量的初始化方式

 -----------------成员变量------------------初始化方式一,在定义变量时直接赋值private final int i = 3;  初始化方式二,声明完变量后在构造方法中为其赋值如果采用用这种方式,那么每个构造方法中都要有j赋值的语句private final int j;  public FinalTest() {j = 3;}  如果取消下面对构造方法的注释,程序就会报错,因此它没有为j赋值/*public FinalTest1(String str) { }*/  为了方便我们可以这样public FinalTest(String str) {this();  调用无参构造器}  如果是下面的代码写法则会报错,因为对j重复赋值/*public FinalTest1(String str1, String str2) {this();j = 3;}*/  初始化方式三,声明完变量后在构造代码块中为其赋值如果采用此方式就不能在构造方法中再次为其赋值构造代码块中的代码会在构造函数之前执行,如果在构造函数中再次赋值就会造成final变量的重复赋值private final int k;  {k = 4;}  -----------------类变量(静态变量)------------------初始化方式一,在定义类变量时直接赋值public final static int p = 3;  初始化方式二,在静态代码块中赋值成员变量可以在构造函数中赋值,但是静态变量却不可以因为成员变量属于对象独有,每个对象创建时只会调用一次构造函数,因此可以保证该成员变量只被初始化一次而静态变量是该类的所有对象共有,每个对象创建时都会对该变量赋值这样就会造成变量的重复赋值public final static int q;  static {q = 3;}

再来看abstract修饰符

首先来看抽象类

抽象类不能用来实例化对象。声明抽象类的唯一目的是为了将来对该类进行扩充。一个类不能同时被abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。抽象类可以包含抽象方法和非抽象方法 

abstract class Caravan{private double price;private String model;private String year;public abstract void goFast();  public abstract void changeColor();
}

如上的goFast()和changeColor()就是抽象方法

抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。抽象方法不能被声明成 final 和 static。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。抽象方法的声明以分号结尾,例如:public abstract sample(); 

public abstract class SuperClass{abstract void m();     抽象方法
}class SubClass extends SuperClass{实现抽象方法void m(){.........}
}

synchronized 关键字声明的方法同一时间只能被一个线程访问
synchronized 修饰符可以应用于四个访问修饰符

public synchronized void showDetails(){.......
}

序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型 

public transient int limit = 55;    不会持久化public int b;  持久化   

    当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复

定义一个需要序列化的类class People implements Serializable{String name; transient Integer age; public People(String name,int age){this.name = name;this.age = age;      }public String toString(){return "姓名 = "+name+" ,年龄 = "+age;     }}public class TransientPeople {public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {People a = new People("李雷",30);System.out.println(a); 打印对象的值ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d://people.txt"));os.writeObject(a);    写入文件(序列化)os.close();ObjectInputStream is = new ObjectInputStream(new FileInputStream("d://people.txt"));a = (People)is.readObject();    将文件数据转换为对象(反序列化)System.out.println(a);      年龄 数据未定义is.close();}
}运行结果如下姓名 = 李雷 ,年龄 = 30
姓名 = 李雷 ,年龄 = null

 volatile修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个volatile 对象引用可能是 null

public class MyRunnable implements Runnable{private volatile boolean active;public void run(){active = true;while (active){    第一行代码}}public void stop(){active = false;  第二行}
}

 通常情况下,线程A调用 run() (在 Runnable 开启的线程),线程B调用 stop() 。如果 第一行 中缓冲区的 active 值被使用,那么在第二行 的 active 值为 false 时循环不会停止。但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止

volatile可以用在任何变量前面,但不能用于final变量前面。因为final型的变量是禁止修改的。使用场景之一:单例模式中采用DCL双锁检测(double checked locking)机制。在多线程访问的情况下可使用volatitle修改来保证多线程下的可见性。缺点是性能有损失,因此单线程情况下不必用此修饰符

class Singleton{private volatile static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if(instance==null) {synchronized (Singleton.class) {if(instance==null)instance = new Singleton();}}return instance;}
}

访问修饰符中一些值得注意得地方

        Private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。被声明为 public
的类、方法、构造方法和接口能够被任何其他类访问;protected 访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected

2.7、具体使用对象

        public   使用对象最广:类、接口、变量、方法

        default  使用对象:类、接口、变量、方法。(即缺省,什么也不写)
        protected使用对象:变量、方法 注意:不能修饰类(外部类)

        private  使用对象:变量、方法 注意:不能修饰类(外部类)

        abstract使用对象:类、接口、方法
        static  使用对象:类、变量、方法、初始化函数(注意:修饰类时只能修饰 内部类 )
        final   使用对象:类、变量、方法

        transient:告诉编译器,在类对象序列化的时候,此变量不需要持久保存
        volatile:指出可能有多个线程修改此变量,要求编译器优化以保证对此变量的修改能够被正确处理

        native:用该修饰符定义的方法在类中没有实现,而大多数情况下该方法的实现是用
CC++编写的
        synchronized:修饰方法,多线程的支持

注:static修饰的初始化函数实际就是指的静态代码块(static初始化函数(static initializer)是一段在加载类时会执行的程序代码。它会在其他程序可以使用该类之前就执行。具体是static初始化函数是由类调用的。类调用时先执行static初始化函数,然后才执行主函数的)

类分外部类和内部类,他们的访问控制是相同的吗?
   内部类是定义在类里面的类,外部类是相对于内部类而言的

外部类的修饰符有
        default(缺省,不写):类定义时前面未加任何修饰符,表示同一个包中可见
        public:修饰类时表示该类能被项目中所有类可见
        abstract:表示是抽象类
        final:表示类不可以被继承
        scrictpf:(java关键字) 当对一个类或接口使用 strictfp 关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754 算法对操作数预期的结果,以单精度和双精度格式表示

注:外部类只能使用public和default


内部类又分:成员内部类、静态内部类、匿名内部类、局部内部类
  成员内部类:作为外部类的一个成员存在,与外部类的属性、方法并列
  静态内部类:使用static修饰的内部类
  局部内部类:定义在外部类的方法体里面的类
  匿名内部类:就是没有名字的内部类

成员内部类修饰符有
        private:private不能修饰外部类

        public        存疑
        protected

        abstract
        final
        static:可以当做普通类使用而不用先实例化一个外部类
        strictfp:(java关键字) 即 strict float point (精确浮点)(可修饰类、接口、方法)


局部内部类
  局部内部类就是在类内的方法中定义的类
  局部类有一个优势,即对外部世界完全隐藏。即使是同一个类中其他的方法也不能访问它
  局部类可以访问包含它的外部类,同时也可以访问局部变量
  局部类不能用public或private访问说明符进行声明,他的作用域被限定在这个方法中


接口修饰符
  public:所有包可见
  default:(缺省)同一个包中可见
  strictfp:(java关键字) 即 strict float point (精确浮点)

3、总结

先看案例,后看结论

3.1、案例

protected修饰的,可以被本类、同包类、(可以是不同包的)子类访问

但在实际使用中,不同包中的子类要访问父类中protected权限的成员却不是那么随意的调用

ch13Test包中定义父类Animal,包含一个protected权限的成员变量 i 和成员方法eat()package ch13Test;public class Animal {protected int i = 5;protected void eat() {System.out.println("Animals eat.");}
}

情况1:子类Cat定义在ch13包中,在子类中直接使用Animal的protected成员变量和方法,可行 

package ch13;import ch13Test.Animal;public class Cat extends Animal{public void eat() {i = 7;eat();System.out.println("Cat is eating" + i);}
}

情况2:子类Cat定义在ch13包中,在子类中通过子类的对象访问Animal的protected成员变量和方法,可行 

package ch13;import ch13Test.Animal;public class Cat extends Animal{public void show() {Cat cat = new Cat();cat.i = 10;cat.eat();System.out.println("Cat is eating" + cat.i);}
}

情况3:子类Cat定义在ch13包中,在子类中通过父类的对象访问父类Animal的protected成员变量和方法,不行 

package ch13;import ch13Test.Animal;public class Cat extends Animal{public void show() {Animal animal = new Animal();// 无法通过父类对象访问父类的protected成员
//        animal.i = 9;
//        animal.eat();
//        System.out.println("Cat is eating" + animal.i);}
}

这一点其实前面遇到过,这里是父类引用去调用,看父类引用初始化的位置,是子类中就不行了,这个看位置的

情况4:在ch13包中新定义Dog类,Dog类也继承Animal。接着在Dog子类中通过其他子类(Cat)的对象访问父类Animal的protected成员变量和方法,不行 

package ch13;import ch13Test.Animal;public class Dog extends Animal{public void show() {Cat cat = new Cat();// 无法通过其他子类对象访问父类的protected成员
//        cat.i = 9;
//        cat.eat();}
}

情况5:子类Cat定义在ch13包中,同包中其他类中通过子类的对象访问父类Animal的protected成员变量和方法,不行 

package ch13;public class Test {public static void main(String[] args) {Cat cat = new Cat();
//        cat.i = 9;
//        cat.eat();}
}

总结如下

1. 子类可以通过继承获得不同包父类的protected权限成员变量和成员方法,在子类中可以直接访问

2. 在子类中可以通过子类的对象访问父类的protected成员变量和方法

3. 在子类中反而不能通过父类的对象访问父类的protected成员变量和方法

4. 在子类中不能通过其他子类的对象访问父类的protected成员变量和方法

5. 在与子类同包的其他类中不能通过子类的对象访问父类的protected成员变量和方法

实例化父类去调用protected修饰的方法,不行。应该

不同包下,子类可通过关键词super访问父类中的protected修饰的方法和属性。super.opendoor1();

或直接通过父类引用访问

不同包下,jvm解析不到是否是子类访问的情况,虽然你是在子类中定义了父类引用。
通过super,jvm就知道是子类要访问父类的protected方法

3.2、结论

常用的是private、default、protected、public、static、final、abstract等修饰符

1、所有的修饰符可以叫"作用域修饰符"或者"修饰符列表",也可以简单点就叫"修饰符"。是一组限定类、属性或方法是否可以被程序里的其他部分访问和调用的修饰符

2、本篇研究的是常用的修饰符,再可以具体、严谨点管"private、default、protected、public"这四个为一组叫"可见性修饰符"、"可访问性修饰符"、"访问控制修饰符"、"访问修饰符",管"static、final、abstract、synchronized、volatile"叫做非访问修饰符(我倾向管前者叫可见性修饰符,管后者叫非访问修饰符)

3、第一组:可见性修饰符

关于可见性修饰符其实记住下表很够用了 ,虽然只是基础

中文可访问范文
private私有表示本类私有,仅允许本类中访问
default默认xx本类、同一包下的类xx
protected受保护的xx本类、同包类、(可以是不同包下的)子类xx
public公开xx任意位置xx

        当可见性修饰符针对的仅是类及类的成员,那么知道"修饰的范围分类和类的成员"即可,具体是"public和default可以修饰类及类的成员,而private和protected只可以修饰类的成员"

        default修饰的可以被称为"包私有(package-private)"和"包内访问(package-access)"。注意这里的英文单词package-private,不要看到private就认为是在说"private修饰啥啥的"。包私有、包内访问,都是在说可访问的范围是本包内而已

        可见性修饰符不是乱选的。一般习惯用public修饰简单省事,但是可见性修饰符的选择应当根据受限范围再定,限定在合适的范围内最好。再实际运用可见性修饰符需要结合案例多加体会,这里不整理了

        类的访问控制符只能是空或者 public,对应前面说的"private和protected只能修饰类的成员,public和protected可以修饰类和类的成员"(此时的范围依旧不是很具体)

        方法和属性的访问控制符有 4 个,分别是 public、 private、protected 和 friendly,friendly就是default,换个名而已,再之前说的包访问这里可以称为友元(friend)。限制范围不变

受限范围具体讲讲就是

前面说的是"public和default可以修饰类和类的成员,而protected和private只能修饰类的成员",实际是

1、protected不能修饰外部类,但可以修饰内部类

2、private不可以修饰外部类,但可以修饰内部类

3、protected 访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected

4、第二组:认识非访问修饰符

可见性修饰符是指能够控制类、成员变量、方法的使用权限的关键字,可以使用它来保护对类、变量、方法和构造方法的访问。包含static、final、abstract、synchronized、volatile、transient

static:修饰变量称为静态变量

static修饰类只能修饰内部类,用他修饰后就成了静态内部类。静态内部类可以当做普通类使用而不用先实例化一个外部类

static可以用在修饰类、变量、方法、初始化函数

final:修饰变量称为常量。常量只可以在声明时初始化,意味着只能赋值一次。如果给常量赋值的是对象,那么对象不可变但对象内的值可变 ; 修饰类使得该类不能被继承;修饰方法使得该方法不能被重写。final 修饰符通常和 static 修饰符一起使用来创建静态常量 

final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。final变量定义的时候可以先声明而不给初值。这种变量也称为final空白。无论什么情况,编译器都确保空白final在使用之前必须被初始化。final空白的存在使得在使用final关键字上留有了更大的灵活性,指的是一个类中的final数据成员就可以实现依对象而有所不同却有保持其恒定不变的特征->final空白如何确保使用前被初始化呢?final修饰实例变量可以在调用构造方法是传参赋值、或者将赋值操作写进构造方法内、或者借助构造代码块使得每一次执行构造方法前去赋值;final修饰静态变量只能声明时初始化

abstract:可以用在修饰类、接口、方法。修饰类成为抽象类。抽象类不能实例化 ; 修饰方法称为抽象方法。有抽象方法的类则该类必定是抽象类,但抽象类中不一定有抽象方法 ; 不能修饰变量

抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。抽象方法不能被声明成 final 和 static。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类 

声明抽象类的唯一目的是为了将来对该类进行扩充。一个类不能同时被abstract 和 final 修饰

synchronized 和 volatile修饰符,主要用于线程的编程。synchronized 关键字声明的方法同一时间只能被一个线程访问
synchronized 修饰符可以应用于四个访问修饰符

序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型

volatile修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个volatile 对象引用可能是 null


http://chatgpt.dhexx.cn/article/oNjInYwm.shtml

相关文章

四种访问修饰符

Java中修饰符分为两种&#xff1a;访问修饰符和非访问修饰符。修饰符中&#xff0c;有一些修饰符可以既可以修饰类&#xff0c;也可以修饰方法&#xff0c;但是有一些修饰符只能修饰符方法。 今天这篇文章先介绍一下四种访问修饰符。 1、private修饰符 private表示私有的。既…

JAVA的四种访问修饰符

JAVA中的访问修饰符&#xff0c;主要用于设置类、属性、方法的访问级别&#xff0c;有以下四种&#xff1a; 修饰符同一个类同一个包子类任何地方public(公共的)YYYYprotected(受保护的)YYYdefault&#xff08;默认的&#xff09;YYprivate&#xff08;私有的&#xff09;Y 1…

特征工程—数据无量纲化之归一化

在sklearn中使用preprocessing预处理与impute缺失值处理&#xff0c;两个模块进行数据预处理 数据无量纲化&#xff1a;将不同量纲的数据转化到同一区间&#xff0c;避免某一取值的数据范围太大或太小对影响计算&#xff0c;加快求解速度&#xff0c;提高精度 无量纲化包括线…

数据挖掘的步骤——降维处理前一定记得进行无量纲化处理

数据挖掘的步骤 我们使用sklearn进行虚线框内的工作&#xff08;sklearn也可以进行文本特征提取&#xff09;。通过分析sklearn源码&#xff0c;我们可以看到除训练&#xff0c;预测和评估以外&#xff0c;处理其他工作的类都实现了3个方法&#xff1a;fit、transform和fit_tra…

#第27篇分享:数据无量纲化(python语言:sklearn 预处理及特征工程)(3)

#数据挖掘五大流程&#xff1a;获取数据&#xff0c;数据预处理 &#xff08;更改数据类型&#xff0c;有噪声&#xff0c;有缺失&#xff09;&#xff0c;特征工程 &#xff08;归一化&#xff0c;标准化&#xff0c;正则化&#xff0c;降维&#xff09;&#xff0c;建模&…

均值归一化_数据无量纲化处理(归一化VS标准化)

常见的无量纲化处理方法主要有极值化、标准化、均值化和标准差化方法&#xff0c;而最常使用的是标准化方法。 标准化方法处理后的各指标均值都为0,标准差都为1,它只反映了各指标之间的相互影响,在无量纲化的同时也抹杀了各指标之间变异程度上的差异,因此,标准化方法并不适用于…

特征工程:特征预处理(无量纲化处理)

文章目录 一、解释二、归一化三、标准化★一、解释 特征预处理API sklearn.preprocessing为什么要做归一化/标准化? 无量纲化 特征的单位或者数量相差较大,这样某特征会‘绝对’最终结果,使得其他算法无法学习到其他特征。 二、归一化 将原始数据进行变换将数据映…

为什么梯度的负方向是梯度下降最快的方向

文章目录 梯度与导数的关系梯度下降算法梯度方向是上升方向一阶泰勒展开式与负梯度 梯度与导数的关系 梯度方向指向数值增长最快的方向&#xff0c;大小为变化率。通过这个性质也说明梯度是有方向和大小的矢量。通过梯度的定义我们发现&#xff0c;梯度的求解其实就是求函数偏…

数字图像处理 基于matlab、opencv计算图像的梯度方向和梯度幅值

一、图像的梯度 1、简述 图像可以被视为标量场(即二维函数)。 通过微分将标量场转换为矢量场。 梯度是一个向量,描述了在x或y方向上移动时,图像变化的速度。我们使用导数来回答这样的问题,图像梯度的大小告诉图像变化的速度,而梯度的方向告诉图像变化最…

梯度方向直方图Histogram of Oriented Gradients (HOG)

在学习HOG特征的时候&#xff0c;发现一片英文文章讲得浅显易懂。因此翻译在这里学习。(文中的图片均来自翻译原文) 原文链接&#xff1a;Histogram of Oriented Gradients 什么是特征描述子 特征描述子一张图片或者一个图片块的一种表示&#xff0c;通过提取有用信息并扔掉…

为什么梯度方向一定是函数增大的方向

全微分的定义 如果函数在区域D内各点处都可微分&#xff0c;那么称这个函数在D内可微分。 以上就是为了解释一下为啥 f ( x Δ x , y Δ y ) − f ( x , y ) f x ′ f(x\Delta x, y\Delta y)-f(x, y)f_{x}^{} f(xΔx,yΔy)−f(x,y)fx′​△x f y ′ f_{y}^{} fy′​△y …

为什么沿梯度方向,函数变化最快???

很多时候&#xff0c;我们时间有限&#xff0c;对一些知识只能不求甚解&#xff0c;但这这些不求甚解的知识又会很困扰我们&#xff0c;总想着原理是啥&#xff0c;为啥这样做。就比如我们学梯度下降时&#xff0c;都知道梯度下降是机器学习、深度学习的核心优化算法&#xff0…

机器学习算法篇:从为什么梯度方向是函数变化率最快方向详谈梯度下降算法

前言&#xff1a;若需获取本文全部的手书版原稿资料&#xff0c;扫码关注公众号&#xff0c;回复: 梯度下降法 即可获取。 原创不易&#xff0c;转载请告知并注明出处&#xff01;扫码关注公众号【机器学习与自然语言处理】&#xff0c;定期发布知识图谱&#xff0c;自然语言处…

⚡可行梯度方向法⚡(Feasible Gradient Direction Method ,FGDM)

⚡最近很烦⚡ 有一阵子没更新了&#xff0c;感觉整个暑假被忽悠了&#xff0c;六月份找Boss指明了一个Direction&#xff0c;然后整个暑假都在忙于补充Proposal相关的Knowledge&#xff0c;但是&#xff0c;被忽悠局局长Boss给忽悠了&#xff08;谁人能明白其中的难受&#xff…

梯度方向为何变化率最大

梯度(本质上是一个向量&#xff09;是机器学习里面的重要基础&#xff0c;借助梯度下降才能最小化损失函数&#xff0c;逐步更新网络参数&#xff0c;得到最佳的函数表示。梯度方向的变化率最大&#xff0c;沿着梯度的反方向&#xff0c;可以最大效率的降低损失函数。在对梯度的…

梯度下降算法过程及为什么负梯度方向是下降最快方向(附代码)

对于梯度下降算法我们熟知的一个例子就是下山问题&#xff0c;当我们位于山的某一点处&#xff0c;沿着当前位置寻找山坡最陡方向以一定步长进行移动&#xff0c;直到走到山脚。那么这个过程具体是怎么做到的&#xff1f;为什么说负梯度方向是下降最快方向呢&#xff1f; 首先…

微积分:如何理解方向导数与梯度?

文章目录 前言方向导数梯度方向导数公式的证明 前言 前文介绍了多元函数微分的实质&#xff0c;接下来介绍多元函数中的方向导数与梯度&#xff0c;以二元函数为例 方向导数 方向导数的实质&#xff1a;自变量沿着xoy平面上的某个方向变化时&#xff0c;f的变化率&#xff0…

Opencv中计算梯度、梯度幅值以及梯度方向的相关函数

在进行图像处理中&#xff0c;经常会计算图像的梯度、梯度幅值以及梯度等&#xff0c;对于不太了解opencv的&#xff0c;可能会自己写计算梯度、梯度幅值和梯度方向的函数&#xff0c;其实这些工作OpenCV都已经为我们做了。下面来看看Opencv中的相关函数&#xff1a; 1&#xf…

梯度方向,梯度下降法,牛顿法

梯度、等高线切线、方向导数 一、直观理解梯度方向与等高线的切线方向垂直 二、方向导数梯度是函数上升的方向&#xff0c;且在该方向上的方向导数最大 三、从泰勒级数展开来看四、牛顿法五、梯度下降与牛顿法的区别 一、直观理解 梯度方向与等高线的切线方向垂直 假设一函数为…

函数的梯度方向和切线方向_导数、方向导数与梯度

导数,方向导数,切线、梯度是从高中就开始接触的概念,然而对这几个概念的认识不清,困惑了我很长时间,下面我将以图文并茂的形式,对这几个概念做详细的解释。 1, 导数 定义:设函数y=f(x)在点x0的某个邻域内有定义,当自变量x在x0处有增量Δx,(x0+Δx)也在该邻域内时,相…