Java语法糖

4 篇文章 0 订阅
1 篇文章 0 订阅

语法糖

编译期处理(javac)

定义

  • 编译器在编译期javac会进行一些优化处理(语法糖)
  • 是指在java编译器把*.java源码编译成*.class字节码大的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是java编译器给的一些福利

默认构造器

  • 不写构造方法时 ,编译器会默认生成一个无参的构造方法

自动拆装箱

  • JDK5之后加入

  • Integer x = 1 ;
    int y = x;
    
  • Integer x = Integer.valueOf(1);  // -128 到 127 重用对象
    int y = x.intValue();
    
  • D:\ideaworkspace\untitled\out\production\untitled>javap -v Test.class
    Classfile /D:/ideaworkspace/untitled/out/production/untitled/Test.class
      Last modified 2021-7-26; size 522 bytes
      MD5 checksum 35e7d1e3c1ce663bac233354ea39616f
      Compiled from "Test.java"
    public class Test
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #5.#23         // java/lang/Object."<init>":()V
       #2 = Methodref          #24.#25        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       #3 = Methodref          #24.#26        // java/lang/Integer.intValue:()I
       #4 = Class              #27            // Test
       #5 = Class              #28            // java/lang/Object
       #6 = Utf8               <init>
       #7 = Utf8               ()V
       #8 = Utf8               Code
       #9 = Utf8               LineNumberTable
      #10 = Utf8               LocalVariableTable
      #11 = Utf8               this
      #12 = Utf8               LTest;
      #13 = Utf8               main
      #14 = Utf8               ([Ljava/lang/String;)V
      #15 = Utf8               args
      #16 = Utf8               [Ljava/lang/String;
      #17 = Utf8               x
      #18 = Utf8               Ljava/lang/Integer;
      #19 = Utf8               y
      #20 = Utf8               I
      #21 = Utf8               SourceFile
      #22 = Utf8               Test.java
      #23 = NameAndType        #6:#7          // "<init>":()V
      #24 = Class              #29            // java/lang/Integer
      #25 = NameAndType        #30:#31        // valueOf:(I)Ljava/lang/Integer;
      #26 = NameAndType        #32:#33        // intValue:()I
      #27 = Utf8               Test
      #28 = Utf8               java/lang/Object
      #29 = Utf8               java/lang/Integer
      #30 = Utf8               valueOf
      #31 = Utf8               (I)Ljava/lang/Integer;
      #32 = Utf8               intValue
      #33 = Utf8               ()I
    {
      public Test();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 6: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   LTest;
    
      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=1, locals=3, args_size=1
             0: iconst_1
             1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
             4: astore_1
             5: aload_1
             6: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
             9: istore_2
            10: return
          LineNumberTable:
            line 8: 0
            line 9: 5
            line 10: 10
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      11     0  args   [Ljava/lang/String;
                5       6     1     x   Ljava/lang/Integer;
               10       1     2     y   I
    }
    SourceFile: "Test.java"
    
    

泛型擦除

  • JDK 5之后加入的特性,在java编译泛型代码后会执行泛型擦除的动作,即泛型信息在编译为字节码之后就消失了,实际类型都当作了Object类型来处理

  • import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Author: sunyang
     * @Date: 2021/7/26
     * @Description:
     */
    public class Test {
        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            list.add(10); // 实际调用的是List.add(Object e)  先把10转成Integer对象类型 再转成Object类型 list.add(Object(.valueOf(10))
            Integer x = list.get (0); // 实际调用的是Object ojb = List.get(int index);
        }
    }
    
  • Classfile /D:/ideaworkspace/untitled/out/production/untitled/Test.class
      Last modified 2021-7-26; size 751 bytes
      MD5 checksum 553b43afaaf7fb2325a1cbe57547837c
      Compiled from "Test.java"
    public class Test
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #9.#29         // java/lang/Object."<init>":()V
       #2 = Class              #30            // java/util/ArrayList
       #3 = Methodref          #2.#29         // java/util/ArrayList."<init>":()V
       #4 = Methodref          #7.#31         // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       #5 = InterfaceMethodref #32.#33        // java/util/List.add:(Ljava/lang/Object;)Z
       #6 = InterfaceMethodref #32.#34        // java/util/List.get:(I)Ljava/lang/Object;
       #7 = Class              #35            // java/lang/Integer
       #8 = Class              #36            // Test
       #9 = Class              #37            // java/lang/Object
      #10 = Utf8               <init>
      #11 = Utf8               ()V
      #12 = Utf8               Code
      #13 = Utf8               LineNumberTable
      #14 = Utf8               LocalVariableTable
      #15 = Utf8               this
      #16 = Utf8               LTest;
      #17 = Utf8               main
      #18 = Utf8               ([Ljava/lang/String;)V
      #19 = Utf8               args
      #20 = Utf8               [Ljava/lang/String;
      #21 = Utf8               list
      #22 = Utf8               Ljava/util/List;
      #23 = Utf8               x
      #24 = Utf8               Ljava/lang/Integer;
      #25 = Utf8               LocalVariableTypeTable
      #26 = Utf8               Ljava/util/List<Ljava/lang/Integer;>;
      #27 = Utf8               SourceFile
      #28 = Utf8               Test.java
      #29 = NameAndType        #10:#11        // "<init>":()V
      #30 = Utf8               java/util/ArrayList
      #31 = NameAndType        #38:#39        // valueOf:(I)Ljava/lang/Integer;
      #32 = Class              #40            // java/util/List
      #33 = NameAndType        #41:#42        // add:(Ljava/lang/Object;)Z
      #34 = NameAndType        #43:#44        // get:(I)Ljava/lang/Object;
      #35 = Utf8               java/lang/Integer
      #36 = Utf8               Test
      #37 = Utf8               java/lang/Object
      #38 = Utf8               valueOf
      #39 = Utf8               (I)Ljava/lang/Integer;
      #40 = Utf8               java/util/List
      #41 = Utf8               add
      #42 = Utf8               (Ljava/lang/Object;)Z
      #43 = Utf8               get
      #44 = Utf8               (I)Ljava/lang/Object;
    {
      public Test();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 9: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   LTest;
    
      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=3, args_size=1
             0: new           #2                  // class java/util/ArrayList
             3: dup
             4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
             7: astore_1
             8: aload_1
             9: bipush        10
            11: invokestatic  #4                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
            14: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
            19: pop
            20: aload_1
            21: iconst_0
            22: invokeinterface #6,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
            27: checkcast     #7                  // class java/lang/Integer
            30: astore_2
            31: return
          LineNumberTable:
            line 11: 0
            line 12: 8
            line 13: 20
            line 14: 31
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      32     0  args   [Ljava/lang/String;
                8      24     1  list   Ljava/util/List;
               31       1     2     x   Ljava/lang/Integer;
          LocalVariableTypeTable: // 局部变量类型表
            Start  Length  Slot  Name   Signature
                8      24     1  list   Ljava/util/List<Ljava/lang/Integer;>; // 泛型 
    }
    
    
  • 所以在取值时,编译器真正生成的字节码中,还要额外做一个强制类型转换的操作

    • // 需要将Object 转化为Integer
      Integer x = (Integer)list.get(0);
      
  • 如果前面的x变量类型修改为int基本类型,那么最终生成的字节码是

    • // 伪代码  需要将Object转为Integer
      int x = ((Integer)list.get(0)).intValue();
      
  • 局部变量中的泛型不会被擦除,但不能通过反射获得,仍然能通过反射获得的这些泛型信息:

    • 返回值 及参数列表

    • import java.lang.reflect.Method;
      import java.lang.reflect.ParameterizedType;
      import java.lang.reflect.Type;
      import java.util.List;
      import java.util.Map;
      import java.util.Set;
      
      /**
       * @program: jvmstudy
       * @description: Demo
       * @author: SunYang
       * @create: 2021-07-22 22:40
       **/
      public class SynchronizedDemo {
          public static void main(String[] args) throws NoSuchMethodException {
      
              Method test = SynchronizedDemo.class.getMethod("test", List.class, Map.class);
              Type[] genericParameterTypes = test.getGenericParameterTypes();
              for (Type genericParameterType : genericParameterTypes) {
                  if (genericParameterType instanceof ParameterizedType) {
                      ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
                      System.out.println("原始类型 - " + parameterizedType.getRawType());
                      Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                      for (int i = 0 ; i < actualTypeArguments.length; i ++ ){
                          System.out.printf("泛型参数[%d] - %s\n", i, actualTypeArguments[i]);
                      }
                  }
              }
      
          }
          public Set<Integer> test(List<String> list, Map<Integer, Object> map) {
              return null;
          }
      
      }
      
    • 原始类型 - interface java.util.List
      泛型参数[0] - class java.lang.String
      原始类型 - interface java.util.Map
      泛型参数[0] - class java.lang.Integer
      泛型参数[1] - class java.lang.Object
      
      

可变参数

  • import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-22 22:40
     **/
    public class SynchronizedDemo {
        public static void main(String[] args){
    
                foo("hello", "word");
    
        }
       public static void foo (String... args) {
            String[] array = args; // 直接赋值
           System.out.println(array);
       }
    
       /**
        *  public static void foo (String[] args) {
        *         String[] array = args; // 直接赋值
        *        System.out.println(array);
        *    }
        *    public static void main(String[] args){
        *
        *             foo(new String[] {"hello", "word"});
        *
        *     }
        *
        * **/
    
    }
    
  • 可变参数String… args其实是一个String[] args, 编译器会在编译期间 将上面代码转化成下面注释掉的代码,就是动态生成了一个长度为二的数组,

  • 如果传的参数为空,则传过去的不是null 而是new String[]{}

foreach 循环

  • JDK5以后

  • import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-22 22:40
     **/
    public class SynchronizedDemo {
        public static void main(String[] args){
    
            int[] array = {1, 2, 3, 4, 5}; // 数组赋初值也是语法糖
            for (int i : array) {
                System.out.println(i);
            }
        }
    
    
          // 编译器编译后的伪代码
    //      public static void main(String[] args){
    //
    //          int[] array = new int[]{1, 2, 3, 4, 5}; // 数组赋初值也是语法糖
    //          for (int i = 0 ; i < array.length; ++i) {
    //              int i = array[i];
    //              System.out.println(i);
    //          }
    //      }
    
    }
    
  • import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-22 22:40
     **/
    public class SynchronizedDemo {
        public static void main(String[] args) {
    
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
            // 数组赋初值也是语法糖
            for (Integer i : list) {
                System.out.println(i);
            }
        }
    
    
        // 编译器编译后的伪代码
    //      public static void main(String[] args){
    //
    //         List<Integer> list = Arrays.asList(1,2,3,4,5);
    //         Iterator iter = list.iterator();
    //         while (iter.hasNext()) {
    //            Iteger i = (Integer)iter.next();
    //        	  System.out.println(i);
    //    }
    //      }
    
    }
    
  • foreach循环写法 ,能够配合数组,以及实现了Iterable 接口的集合类一起使用,其中Iterable用来获取集合的迭代器(Iterator)

Switch字符串

  • JDK 7开始,switch可以使用字符串和枚举类,语法糖

  • import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-22 22:40
     **/
    public class SynchronizedDemo {
    
        public static  void choose (String str) {
            switch (str) {
                case "hello": {
                    System.out.println("h");
                    break;
                }
                case "world": {
                    System.out.println("w");
                    break;
                }
            }
        }
    //     public static void choose (String str) {
    //         byte x = -1;
    //         switch (str.hashCode()) {
    //             case 99162322:  // hello 的  hashCode
    //                 if (str.equals("hello")) {  // 避免发生hash冲突
    //                     x = 0;
    //                 }
    //                 break;
    //             case 113318802: // world的hashCode
    //                 if (str.equals("world")) {
    //                     x = 1;
    //                 }
    //         }
    //
    //         switch (x) {
    //             case 0:
    //                 System.out.println("h");
    //                 break;
    //             case 1:
    //                 System.out.println("w");
    //         }
    //     }
    
    }
    

switch 枚举

  • import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-22 22:40
     **/
    public class SynchronizedDemo {
        enum Sex {
            MALE, FEMALE
        }
    
        public static void main(String[] args) {
            choose(Sex.MALE);
        }
    
        public static void choose(Sex sex) {
            switch (sex) {
                case MALE: {
                    System.out.println("男");
                    break;
                }
                case FEMALE: {
                    System.out.println("女");
                    break;
                }
            }
        }
    
        /**
         * 定义一个合成类(仅jvm使用,对我们不可见)
         * 用来映射枚举的ordinal与数组元素的关系(每个枚举都有自己的ordinal枚举编号 正好和数组下标一样)
         * 枚举的ordinal 表示枚举对象的序号,从 0开始
         * 即MALE 的ordinal() = 0, FEMALE 的ordinal() = 1
         * $MAP 字节码中的名字不叫这个
         * **/
    //    static class $MAP {
    //        // 数组大小即为枚举元素的个数,里面存储case用来对比的数字
    //        static  int [] map = new int[2];  // 定义一个和枚举个数相同的数组
    //        static {
    //            map[Sex.MALE.ordinal()] = 1;
    //            map[Sex.FEMALE.ordinal()] = 2;
    //        }
    //    }
    //
    //    public static void choose(Sex sex) {
    //        int x = $MAP.map[sex.ordinal()];
    //        switch (x) {
    //            case 1:
    //                System.out.println("男");
    //                break;
    //            case 2:
    //                System.out.println("女");
    //                break;
    //        }
    //    }
    
    }
    

枚举类

  • /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-26 21:20
     **/
    public enum Sex {
        MALE,
        FEMALE
    }
        /**
         * 本质上也是一个类,
         * 两个枚举值实际上就是类两个实例对象
         * 枚举类的实例个数是有限的,而正常类是无限的
         * **/
    
    //public final class Sex extends Enum<Sex> {
    //    public static final Sex MALE;
    //    public static  final Sex FEMALE;
    //    private static final Sex[] $VALUES;
    //
    //    static {
    //        MALE = new Sex("MALE", 0);
    //        FEMALE = new Sex("FEMALE", 1);
    //        $VALUES = new Sex[]{MALE, FEMALE};
    //    }
    //
    //    // 防止被使用者 创建实力对象,仅本类使用
    //    private Sex(String name, int ordinal) {
    //        super(name, ordinal);
    //    }
    //    public static Sex[] values(){
    //        return $VALUES.clone();
    //    }
    //    public static Sex valueOf(String name) {
    //        return Enum.valueOf(Sex.class, name);
    //    }
    
    //}
    

try-with-resources

  • JDK 7以后新增,其中资源对象需要实现AutoCloseable接口, 例如 InputStream.,OutputStream,Connection.Statement,ResultSet等接口都实现了AutoCloseable。使用try-with-resources可以不用写finally语句 编译器会自动帮助生成关闭资源代码

  • import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * @program: jvmstudy
     * @description: Demo
     * @author: SunYang
     * @create: 2021-07-26 21:37
     **/
    //public class TryWithResourcesDemo {
    //    public static void main(String[] args) {
    //        try(InputStream is = new FileInputStream("C:\\备份1.txt")) {
    //            System.out.println(is);
    //        } catch (IOException e) {
    //            e.printStackTrace();
    //        }
    //    }
    //}
    
    public class TryWithResourcesDemo {
        public TryWithResourcesDemo(){}
    
        public static void main(String[] args) {
            try {
                InputStream is = new FileInputStream("C:\\备份1.txt");
                Throwable t = null;
                try {
                    System.out.println(is);
                } catch (Throwable e1) {
                    // t 是我们代码中出现的异常(try块可能出现的异常赋值给临时的Throwable对象)
                    t = e1;
                    throw e1;
                } finally {
                    // 判断了资源是否为空
                    if (is != null) {
                        // 如果我们的代码有异常
                        if (t != null) {
                            try {
                                is.close();
                            }catch (Throwable e2) {
                                // 如果close 出现异常,作为被压制异常添加 为了把我们try块中的异常和关闭资源时的异常都保留下来 为了防止异常丢失
                                t.addSuppressed(e2);
                            }
                        } else {
                            // 如果我们代码没有异常, close出现的异常就是最后catch块中的e
                            is.close();
                        }
                    }
    
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 压制异常添加

    • /**
       * @program: jvmstudy
       * @description: Demo
       * @author: SunYang
       * @create: 2021-07-26 21:53
       **/
      public class TWR2 {
          public static void main(String[] args) {
              try(MyResource resource = new MyResource()) {
                  int i = 1/0;
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      
      class MyResource implements AutoCloseable {
          public void close() throws Exception {
              throw  new Exception("close 异常");
          }
      }
      
    • java.lang.ArithmeticException: / by zero
      	at TWR2.main(TWR2.java:10)
      	Suppressed: java.lang.Exception: close 异常
      		at MyResource.close(TWR2.java:19)
      		at TWR2.main(TWR2.java:11)
      
      Process finished with exit code 0
      
      
    • 两个异常都不会丢失

方法重写时的桥接方法

  • 我们都知道方法重写时对返回值分两种情况

    • 父子类的返回值完全一致
    • 子类返回值可以是父类返回值的子类
  • /**
     * @program: jvmstudy
     * @description:
     * @author: SunYang
     * @create: 2021-07-26 21:59
     **/
    public class FuZiDemo {
        public Number m() {
            return 1;
        }
    }
    
    class Zi extends FuZiDemo {
        @Override
        // 子类m方法的返回值是Integer是父类m 方法返回值Number 的子类
        public Integer m() {
            return 2;
        }
    }
    
    //class  Zi extends  FuZiDemo {
    //    // 自己写的原方法会被保留
    //    public Integer m() {
    //        return 2;
    //    }
    //
    //    // 此方法才是真正的重写了父类public Number m() 方法
    //    // 此方法是一个合成方法,仅供JVM使用,我们不可见
         // 允许方法同名,参数一致
    //    public synthetic bridge Number m() {
    //        // 调用 public Integer m()   向上转型 Integer -> Number
    //        return m();
    //    }
    //}
    
  • 用反射代码验证(会有两个m()方法)

    • image-20210726220912196

匿名内部类

  • /**
     * @program: jvmstudy
     * @description:
     * @author: SunYang
     * @create: 2021-07-26 22:11
     **/
    public class NiMingDemo {
        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("ok");
                }
            };
        }
    }
    
    // 额外生成了一个类 实现了Runnable接口
    //final class NiMingDemo$1 implements Runnable {
    //    // 一个无参构造
    //    NiMingDemo$1(){}
    //
    //    // 并重写了run方法
    //    @Override
    //    public void run() {
    //        System.out.println("ok");
    //    }
    //}
    //
    //public class NiMingDemo {
    //    public static void main(String[] args) {
    //        Runnable runnable = new NiMingDemo$1();
    //
    //    }
    //}
    
  • 匿名内部类将这个局部变量的值传入到内部类中,以成员变量的形式存在,值传递由构造函数完成,保证线程安全

  • 为了避免方法内的变量脱离方法而存在的现象发生,于是1.8之前规定内部类不能访问一般的局部变量,但能访问被final修饰的局部变量

  • 1.8之后jvm会自动添加final修饰符 称为effectively final

  • /**
     * @program: jvmstudy
     * @description:
     * @author: SunYang
     * @create: 2021-07-26 22:11
     **/
    public class NiMingDemo {
        public static void test(final int x) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("ok" + x);
                }
            };
        }
    }
    
    // 额外生成了一个类 实现了Runnable接口
    //final class NiMingDemo$1 implements Runnable {
    //
    //    int val$x;
    //    NiMingDemo$1(int x){
    //    this.val$x = x;
    //    }
    //
    //    // 并重写了run方法
    //    @Override
    //    public void run() {
    //        System.out.println("ok" + this.val$x);
    //    }
    //}
    //
    //public class NiMingDemo {
    //    public static void main(String[] args) {
    //        Runnable runnable = new NiMingDemo$1(x);
    //
    //    }
    //}
    
  • 将x作为参数传过来,然后赋值给匿名内部类自己的局部变量,将来用的就是自己内部类的局部变量,

  • 为什么匿名内部类引用外部局部变量时,局部变量为什么必须是final的

    • 因为在创建匿名内部类对象时,将x的值赋值给了NiMingDemo$1 对象的valx属性,所以x不应该在发生变化了,如果发生了变化,那么valx属性也没办法再跟着变化,就会造成数据不一致。

) {
@Override
public void run() {
System.out.println(“ok” + x);
}
};
}
}

// 额外生成了一个类 实现了Runnable接口
//final class NiMingDemoKaTeX parse error: Expected '}', got 'EOF' at end of input: … // int valx;
// NiMingDemoKaTeX parse error: Expected '}', got 'EOF' at end of input: … // this.valx = x;
// }
//
// // 并重写了run方法
// @Override
// public void run() {
// System.out.println(“ok” + this.val$x);
// }
//}
//
//public class NiMingDemo {
// public static void main(String[] args) {
// Runnable runnable = new NiMingDemo$1(x);
//
// }
//}


- 将x作为参数传过来,然后赋值给匿名内部类自己的局部变量,将来用的就是自己内部类的局部变量,

- 为什么匿名内部类引用外部局部变量时,局部变量为什么必须是final的

- 因为在创建匿名内部类对象时,将x的值赋值给了NiMingDemo$1 对象的valx属性,所以x不应该在发生变化了,如果发生了变化,那么valx属性也没办法再跟着变化,就会造成数据不一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值