当前位置: 首页 > 面试题库 >

JVM / Java,是否在运行时强制执行方法可访问性规则?

瞿和硕
2023-03-14
问题内容

我很好奇JVM的工作方式。JVM是否承认诸如“专用”之类的方法可访问性规则受保护,还是仅在编译时完成?

例如,是否可以在第37行附近进行一些字节码操作并调用一个受保护的方法,例如test3?通常,编译器不会让我调用该方法,因为它被声明为protected。但是我很好奇,是否在运行时强制执行了该受保护的规则?

u.test1();
//在运行时是否可以通过字节码操作来调用“ test3”
// @ line37

package org.berlin.algo.basic.test;
public class RunX {
    private String zzz = "rrrrr";    
    public void test1() {
        // Note: I am intentionally use 'new' here as part of my test, not a
        // good practice I know but allowed by the language.
        Object x = new String("Test1 -----[1.1] " + zzz);
        x = new String("Test1 --- [1.2]" + x.toString());
        System.out.println(x);
        this.test2();
        this.test3();
    } 
    /**
     * Here, I noticed that the compiler removed my 'test2' code block.
     * Does that always happen?
     */
    private void test2() {
        Object x = new String("Test2@line21--->>> [2.1]");        
        System.out.println(x);
    }    
    protected void test3() {
        Object x = new String("Test3@line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]");
        x = new String("Test3@line28--->>> [3.2]");
        System.out.println(x);               
    }    
    public static void main(final String [] args) {
        System.out.println("Running");
        RunX u = new RunX();
        u.test1();
        // Is it possible at runtime, to call 'test3' through bytecode manipulation
        // @line37
        System.out.println("Done");
    }    
} // End of the Class //
/* 
 JVM bytecode: javap -v RunX 
 Compiled from "RunX.java"
public class org.berlin.algo.basic.test.RunX extends java.lang.Object
  SourceFile: "RunX.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class    #2; //  org/berlin/algo/basic/test/RunX
const #2 = Asciz    org/berlin/algo/basic/test/RunX;
...
...
const #84 = Asciz   SourceFile;
const #85 = Asciz   RunX.java;

{
public org.berlin.algo.basic.test.RunX();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   ldc #12; //String rrrrr
   7:   putfield    #14; //Field zzz:Ljava/lang/String;
   10:  return
  LineNumberTable: 
   line 3: 0
   line 5: 4
   line 3: 10

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      11      0    this       Lorg/berlin/algo/basic/test/RunX;

public void test1();
  Code:
   Stack=5, Locals=2, Args_size=1
   0:   new #21; //class java/lang/String
   3:   dup
   4:   new #23; //class java/lang/StringBuilder
   7:   dup
   8:   ldc #25; //String Test1 -----[1.1] 
   10:  invokespecial   #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   13:  aload_0
   14:  getfield    #14; //Field zzz:Ljava/lang/String;
   17:  invokevirtual   #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   20:  invokevirtual   #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   23:  invokespecial   #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
   26:  astore_1
   27:  new #21; //class java/lang/String
   30:  dup
   31:  new #23; //class java/lang/StringBuilder
   34:  dup
   35:  ldc #39; //String Test1 --- [1.2]
   37:  invokespecial   #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   40:  aload_1
   41:  invokevirtual   #41; //Method java/lang/Object.toString:()Ljava/lang/String;
   44:  invokevirtual   #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   47:  invokevirtual   #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   50:  invokespecial   #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
   53:  astore_1
   54:  getstatic   #42; //Field java/lang/System.out:Ljava/io/PrintStream;
   57:  aload_1
   58:  invokevirtual   #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   61:  aload_0
   62:  invokespecial   #54; //Method test2:()V
   65:  aload_0
   66:  invokevirtual   #57; //Method test3:()V
   69:  return

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      70      0    this       Lorg/berlin/algo/basic/test/RunX;
   27      43      1    x       Ljava/lang/Object;

protected void test3();
  Code:
   Stack=3, Locals=2, Args_size=1
   0:   new #21; //class java/lang/String
   3:   dup
   4:   ldc #66; //String Test3@line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]
   6:   invokespecial   #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
   9:   astore_1
   10:  new #21; //class java/lang/String
   13:  dup
   14:  ldc #68; //String Test3@line28--->>> [3.2]
   16:  invokespecial   #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
   19:  astore_1
   20:  getstatic   #42; //Field java/lang/System.out:Ljava/io/PrintStream;
   23:  aload_1
   24:  invokevirtual   #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   27:  return

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      28      0    this       Lorg/berlin/algo/basic/test/RunX;
   10      18      1    x       Ljava/lang/Object;
public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   getstatic   #42; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc #72; //String Running
   5:   invokevirtual   #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   new #1; //class org/berlin/algo/basic/test/RunX
   11:  dup
   12:  invokespecial   #76; //Method "<init>":()V
   15:  astore_1
   16:  aload_1
   17:  invokevirtual   #77; //Method test1:()V
   20:  getstatic   #42; //Field java/lang/System.out:Ljava/io/PrintStream;
   23:  ldc #79; //String Done
   25:  invokevirtual   #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   28:  return
  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      29      0    args       [Ljava/lang/String;
   16      13      1    u       Lorg/berlin/algo/basic/test/RunX;
}
 */

问题答案:

到JLS!

15.12.4方法调用的
运行时评估在运行时,方法调用需要五个步骤。首先,可以计算目标参考。其次,对参数表达式进行求值。 第三,检查要调用的方法的可访问性。
第四,找到要执行的方法的实际代码。第五,创建一个新的激活框架,必要时执行同步,并将控制权转移到方法代码。

JLS的措词表示将在运行时检查可访问性。



 类似资料:
  • 问题内容: 假设我在使用Java 8类型注释的类中具有以下成员: 是否可以在运行时使用反射读取在String类型上使用的给定注释?如果是这样,将如何进行? 更新:这是注释类型的定义: 问题答案: 是的,有可能。表示这种结构的反射类型称为。这是如何获取注释的示例:

  • 一点背景:我是一个AEM项目的FE开发人员。该项目是一个SPA AEM作为云服务。我从命令行运行作者实例。 我的电脑规格是: CPU: Intel(R)Core(TM)i5-7400 CPU@3.00GHz 3.00 GHz RAM: 24.0 GB SSD: 476 GB 操作系统:Windows 10 Pro 对于我们正在使用的AEM项目 Javasdk 11 Maven 3.6.3 我已经设

  • 我在HashMap中存储的对象作为键覆盖equals(),但不是hashCode();当我在映射中放置一个对象时,equals()方法没有被调用。如果我还重写hashCode(),则会调用equals()方法。为什么? 为什么我不能使用自定义的equals方法来阻止向映射中添加对象,而不管我是否重写hashCode()? 谢谢 如果注释了hashCode(),则大小为2,否则大小为1。 我在想,如

  • 问题内容: 无论如何在运行时重写方法?即使需要从该实例动态创建子类? 问题答案: 使用纯Java,否。 使用ByteBuddy(首选),asm,cglib或Aspectj时,可以。 在纯Java中,在这种情况下要做的事情是创建一个基于接口的代理,该代理处理方法调用并委托给原始对象(或不委托)。

  • 问题内容: jmap进行内存转储时,我的Java应用程序是否继续运行? 问题答案: 您的应用程序已停止。获得准确的堆转储的唯一实用方法是在创建转储时停止所有应用程序活动。 这是“简短”暂停还是“长时间”暂停取决于要转储多少。如果使用“ -dump”,则将转储整个堆,包括不可达的对象。如果使用“ -dump:live”,则只会转储可访问的对象……但这(至少)需要标记堆以找出可访问的对象。 但是,如果

  • 问题内容: JVM是否可以同时运行多个程序?如果是这样,怎么办?如果没有,为什么? 要运行程序,我们只需 但是我们可以使用同一个JVM实例来运行另一个程序吗? 问题答案: 答案取决于您对“程序”的定义。具有方法并以其开头的Java程序通常无法在同一JVM中运行,因为没有内置的资源或名称空间分隔。例如,如果两个程序使用同一库的冲突版本怎么办? 我们还提供了旨在共享JVM的应用程序,例如企业应用程序。