Java从遗忘到入门——Day03

(昨天没有学习,我有罪)

内部类

内部类可分为成员内部类(非静态内部类,静态内部类),匿名内部类,局部内部类。

非静态内部类

特点:

  1. 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员;
  2. 非静态内部类不能有静态方法、静态属性和静态初始化块。
  3. 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。

eg.

public class Test {
    int age = 20;
    public class Inner {
        int age = 10;
        public void show() {
            int age = 5;
            System.out.println(age); //5
            System.out.println(this.age); //10
            System.out.println(Test.this.age); //20
        }
    }

    public static void main(String[] args) {
        new Test().new Inner().show();
    }
}

静态内部类

特点:

  1. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
  2. 静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。

eg.

class Outer {
    public static class Inner {
        public void show() {
            System.out.println("...");
		}
    }
}

public class Test {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        inner.show();
    }
}

匿名内部类

适合只使用一次的类。多线程时用的多。
eg.

public class anonymityClass {
    
    public void startThread(){
        new Thread(){
            @Override
            public void run(){
                for(int i = 0;i < 10;i++){
                    System.out.println("running..." + i);
                }
            }
        }.start();
    }
}

局部内部类

它是定义在方法内部的,作用域只限于本方法,称为局部内部类。局部内部类在实际开发中应用很少。

public class Test {
    public void show () {
        class Inner {
            void innerShow() {
                System.out.println("...");
            }
        }
        new Inner().innerShow();
    }
    
    public static void main(String[] args) {
        new Test().show();
    }
}

自动拆/装箱

自动装箱与拆箱的功能事实上是编译器来帮的忙,编译器在编译时依据您所编写的语法,决定是否进行装箱或拆箱动作。

自动装箱

Integer i = 100;//自动装箱

相当于编译器自动为您作以下的语法编译:

Integer i = Integer.valueOf(100);

注意:调用的是valueOf(100),而不是new Integer(100)。

自动拆箱

Integer i = 100;
int j = i;//自动拆箱

相当于编译器自动为您作以下的语法编译:

int j = i.intValue();

所以自动装箱与拆箱的功能是所谓的“编译器蜜糖(Compiler Sugar)”,虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。

包装类空指针异常问题

以下代码会发生空指针异常:

Integer i = null;
int j = i;

因为上述代码等价于:

Integer i = null; 
int j = i.intValue();

null表示i没有指向任何对象的实体,但作为对象名称是合法的(不管这个对象名称存是否指向了某个对象的实体)。由于实际上i并没有指向任何对象的实体,所以也就不可能操作intValue()方法,这样上面的写法在运行时就会出现NullPointerException错误。

包装类的缓存问题

整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
下面我们以Integer类为例,看一看Java为我们提供的源码,加深对缓存技术的理解:

public static Integer valueOf(int i) {
     return i >= -128 && i <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[i + 128] : new Integer(i);
}

这段代码中我们需要解释下面几个问题:

  1. IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用。
  2. 一般情况下 IntegerCache.low为-128,IntegerCache.high为127

IntegerCache内部类代码为:

	private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer[] cache;

        private IntegerCache() {
        }

        static {
            int h = 127;
            String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            int i;
            if (integerCacheHighPropValue != null) {
                try {
                    i = Integer.parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    h = Math.min(i, 2147483518);
                } catch (NumberFormatException var4) {
                }
            }

            high = h;
            cache = new Integer[high - -128 + 1];
            i = -128;

            for(int k = 0; k < cache.length; ++k) {
                cache[k] = new Integer(i++);
            }

            assert high >= 127;

        }
    }

由上面的源码我们可以看到,静态代码块的目的就是初始化数组cache的,这个过程会在类加载时完成。

代码测试:

	public static void main(String[] args) {
        Integer in1 = -128;
        Integer in2 = -128;
        System.out.println(in1 == in2);//true 因为123在缓存范围内
        System.out.println(in1.equals(in2));//true
        Integer in3 = 1234;
        Integer in4 = 1234;
        System.out.println(in3 == in4);//false 因为1234不在缓存范围内
        System.out.println(in3.equals(in4));//true
    }

上述代码的内存分析图为:
在这里插入图片描述

已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页