java内部类技术提炼

创作时间:2016.07.28,2016.07.29

本人qq:992591601,欢迎交流。

参考书籍:《Thinking in Java》、《Effective Java》

备注:这篇文章并不打算介绍内部类相关的一切技术细节,在《Thinking in Java》里已经介绍的很详细了,我只想重点谈谈一些我所了解的内部类的应用。顺便提纲挈领的对《Thinking in Java》相应章节作一定总结。

一些提炼:

一.真正的内部类

1.内部类拥有其外部类的所有元素(方法和字段)的访问权(原理在于Java默认做到了:当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。)

2.内部类的创建:

(1)首先,最直接创建内部类的地方只能是在外部类的方法里。

(2)外部类可以写一个工厂方法来返回创建的内部类。

一种形式是这样:OuterClass.InnerClass innerClass = outerClass.getInner();

package cn.j;

/**
 * @ClassName: OutClass
 * @Description: thinking in java
 * @author 无名
 * @date 2016-7-28 下午9:37:59
 * @version 1.0
 */
public class OutClass {
    private int outValue = 1;

    InnerClass getInner() {
        return new InnerClass();
    }

    public void outSay(){
        System.out.println("from out function.");
    }

    class InnerClass {
        public void innerSay() {
            System.out.println("I am inner,and out value = " + outValue);
            outSay();
        }
    }

    public static void main(String[] args) {
        OutClass outClass = new OutClass();
        OutClass.InnerClass innerClass = outClass.getInner();
        innerClass.innerSay();
    }
}

(3)如果内部类实现了某个接口Inter,则可以  Inter innerClass = outerClass.getInner();

这便是内部类的向上造型

package cn.j;

interface Inter{
    public void innerSay();
}

/**
 * @ClassName: OutClass
 * @Description: thinking in java
 * @author 无名
 * @date 2016-7-28 下午9:37:59
 * @version 1.0
 */
public class OutClass {
    private int outValue = 1;

    InnerClass getInner() {
        return new InnerClass();
    }

    public void outSay(){
        System.out.println("from out function.");
    }

    class InnerClass implements Inter{
        @Override
        public void innerSay() {
            System.out.println("I am inner,and out value = " + outValue);
            outSay();
        }
    }

    public static void main(String[] args) {
        OutClass outClass = new OutClass();
        Inter innerClass = outClass.getInner();
        innerClass.innerSay();
    }
}

3.在方法内的内部类,局部内部类:

局部内部类与一般内部类有很多相似之处,在于其对外部类的访问权限上。不同之处,在于对于局部内部类的创建,只能在包含该类的方法之上。

package cn.j;

public class TestLocalInnerClass {
    public int int00 = 1;
    public void outFunc(){
        System.out.println("I am Outter class");
    }
    public void func1(){
        class InnerLocalClass{
            public void say(){
                System.out.println("I am InnerLocalClass value:" + int00);
                outFunc();
            }
        }
        InnerLocalClass ilc = new InnerLocalClass();
        ilc.say();
    }
    public static void main(String[] args){
        TestLocalInnerClass tlic = new TestLocalInnerClass();
        tlic.func1();
    }
}

4.匿名内部类:

要我来做匿名内部类的示例的话,非常简单:

package cn.j;
/**
* @ClassName: MyAnonymousInterface
* @Description: Thinking in Java
* @author 无名
* @date 2016-7-29 下午8:26:52
* @version 1.0
 */
class MyInnerClass {
    private String msg = "A";
    public void say(){
        System.out.println("I am MyInnerClass" + msg);
    }
}
public class AnonymousClassTest {
    public static void main(String[] args){
        new MyInnerClass().say();
    }
}
package cn.j;
/**
* @ClassName: MyAnonymousInterface
* @Description: Thinking in Java
* @author 无名
* @date 2016-7-29 下午8:26:52
* @version 1.0
 */
interface MyAnonymousInterface{
    public void say();
}
public class AnonymousClassTest {
    public static void main(String[] args){
        new MyAnonymousInterface(){
            private String msg = "A";
            public void say(){
                System.out.println("I am MyAnonymousInterface" + msg);
            }
        }.say();
    }
}

先看看第一个示例,再看看第二个示例,很容易看出其中玄机。匿名内部类其实都是,通过new表达式来直接实现一个接口。在这个过程中插入一个类的定义后立刻便new出这个类并使用它。

之前看到类似这样的创建线程的写法,当时还觉得很nb,其实如果熟悉匿名内部类了,再看真的很easy。这种写法可能就是为了装b吧。具体原理在于Thread的创建可以是以一个实现了Runnable接口的类作为参数的,而这个实现了Runnable接口的类在这里以匿名内部类来实现。

总体来讲,配合上面示例1,然后示例2,再加上对Thread创建方式的理解,便可以完全了解下面的代码:

        new Thread(new Runnable()
        {
            public void run()
            {
                while (true)
                {
                    System.out.println("fu波多野结衣ck");
                }
            }
        }).start();

有一点要补充一 下:局部内部类和匿名内部类能且只能访问局部final变量:

类似这样的效果:

package cn.j;

public class TestLocalInnerClass {
    public void func1(){
        final int localV = 3;
        class InnerLocalClass{
            public void say(){
                System.out.println("I am InnerLocalClass value:" + localV);
            }
        }
        InnerLocalClass ilc = new InnerLocalClass();
        ilc.say();
    }
    public static void main(String[] args){
        TestLocalInnerClass tlic = new TestLocalInnerClass();
        tlic.func1();
    }
}

5.嵌套类(static修饰的内部类):

(1)You don‘t need an outer-class object in order to create an object of a nested class.

(2)You can‘t  access a non-static outer-class object from an object of a nested class.

看不懂Thinking in java的英文,看下面的代码也懂了。

package cn.j;

/**
* @ClassName: NestedClassTest
* @Description: Thinking in Java
* @author 无名
* @date 2016-7-29 下午9:33:28
* @version 1.0
 */
public class NestedClassTest {
    private int outV00 = 1;
    public static int outV01 = 1;
    public void outSay00(){
        System.out.println("out say");
    }
    public static void outSay01(){
        System.out.println("out static say");
    }
    public static class NestedC00 {
        private int intV00;
        public void innerFunc(){
            intV00 = outV01;
            outSay01();
        }
    }
    public static void main(String[] args){
        NestedC00 nc00 = new NestedC00();
        nc00.innerFunc();
    }
}

6.接口中的类

接口中的类类似于嵌套类的情况,本身和接口没有本质联系(默认public static),只是处于其命名空间之下

package cn.j;

import cn.j.ClassInInterface.Test;

interface ClassInInterface {
    void func00();
    class Test implements ClassInInterface {
        @Override
        public void func00() {
            System.out.println("Howdy");
        }
    }
}
/**
* @ClassName: ClassInInterfaceTest
* @Description: Thinking in Java
* @author 无名
* @date 2016-7-29 下午9:45:08
* @version 1.0
 */
public class ClassInInterfaceTest {
    public static void main(String[] args) {
        Test test = new Test();
        test.func00();
    }
}

我所知道的内部类的几个应用:

1.《Effective Java》第二章第2条,讲到使用嵌套类完成构建器设计模式。

package cn.j;

public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbonhydrate;

    public static class Builder {
        private final int servingSize;
        private final int servings;

        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbonhydrate = 0;

        public Builder(int servingSize,int serving){
            this.servingSize = servingSize;
            this.servings = serving;
        }

        public Builder calories(int val){
            this.calories = val;
            return this;
        }

        public Builder fat(int val){
            this.fat = val;
            return this;
        }

        public Builder carbonhyate(int val){
            this.carbonhydrate = val;
            return this;
        }

        public Builder sodium(int val){
            this.sodium = val;
            return this;
        }

        public NutritionFacts build(){
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder){
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbonhydrate = builder.carbonhydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();
    }
}

结合代码来看,如果单纯用构造函数来初始化那些参数的话,会比较麻烦,而难以阅读,使用易于出错。

例如new Test(1,2,3,4,5,6,7,8,9);这种写法。

上述代码的形式,NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();可读性非常强。builder模式模拟了具名的可选参数。
                       

2. 项目中遇到的,自定义注解实现前后台参数校验,用到了内部类:

package sonn.sonnannotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

import sonn.util.StringUtill;

/**
* @ClassName: IsValidString
* @Description: 自定义注解实现前后台参数校验,判断是否包含非法字符
* @author 无名
* @date 2016-7-25 下午8:22:58
* @version 1.0
 */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IsValidString.ValidStringChecker.class)
@Documented
public @interface IsValidString
{
    String message() default "The string is invalid.";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default{};

    class ValidStringChecker implements ConstraintValidator<IsValidString,String>
    {

        @Override
        public void initialize(IsValidString arg0)
        {
        }

        @Override
        public boolean isValid(String strValue, ConstraintValidatorContext context)
        {
            if(StringUtill.isStringEmpty(strValue))
            {
                return true;
            }
            if(strValue.contains("<"))
            {
                return false;
            }
            return true;
        }

    }
}

具体内容可以参考我的博文:http://blog.csdn.net/sonnadolf/article/details/52040017

3.之前提到的,匿名内部类创建线程的写法。其实很多时候都可以采用匿名内部类方式实现接口,直接new一个类来使用。只是大家不熟悉这个用法罢了。

4.java jdk的线程池的Executors类,用到了嵌套类。

类似这样:

public class Executors {
    ..........
    static class DefaultThreadFactory implements ThreadFactory {
     ..........
    }
     ..........
}

5.非常非常重要的一点,内部类是tmd可以弥补java无法多继承缺点的啊。虽然我觉得有点扯淡。因为java本身不支持多继承。用内部类不知算什么……

时间: 2024-08-05 06:58:32

java内部类技术提炼的相关文章

Java内部类详解(一)(转自:http://blog.csdn.net/wangpeng047/article/details/12344593)

很多人对于Java内部类(Inner Class)都十分陌生,甚至听都没听过也没有使用过,内部类在Java中其实是比较重要的一块内容,掌握好这门知识对于编程来说,犹如插上一对翅膀. 一.概念 内部类是指在一个外部类的内部再定义一个类,类名不需要和文件名相同. 对于一个名为outer的外部类和其内部定义的名为inner的内部类.编译完成后会生成outer.class和outer$inner.class两个类.所以内部类的成员变量.方法名可以和外部类的相同. 内部类可以是静态static和非静态的,

单例模式的几种实现--《java开发技术-在架构中体验设计模式和算法之美》

package com.doctor.java.design_pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /**  * 单例模式的几种实现--<java开发技术-在架构中体验设计模式和算法之美>  *   * @author doctor  *  * @time 2015年4月24日 下午11:11:03  */ public class SingletonPattern { /**  * @param a

java 反射技术

什么是反射?反射就是将字节码中的各种成分映射到相应的java类中来,java反射技术自JDK1.1以来就出现了,目前大多数流行的框架都采用了这种技术,可见其重要性,这篇文章将详细介绍我对java反射技术的一些研究. 代表字节码对象的Class java中所有的类都有自己特有的一份字节码,当程序调用该类时,JVM便会将这份字节码装载到内存中来.在java中主要有三种方法来得到相应的字节码对象. 通过类的实例的getClass()方法获取,如 Class clazz=new Date().getCl

JAVA读书推荐----《深入分析Java Web技术内幕》--《java多线程编程核心技术》--《大型网站技术架构 核心原理与案例分析》-《Effective Java中文版》

(1)  首先推荐的不是一本书,而是一个博客,也是我们博客园另外一位博友java_my_life. 目前市面上讲解设计模式的书很多,虽然我前面讲了看书是最好的,但是对设计模式感兴趣的朋友们,我推荐的是这个博客.这位博友的设计模式讲得非常非常好,我认为90%的内容都是没有问题且很值得学习的,其讲解设计模式的大体路线是: 1.随便开篇点明该设计模式的定义 2.图文并茂讲解该设计模式中的结构 3.以详细的代码形式写一下该种设计模式的实现 4.补充内容 5.讲解该设计模式的优缺点 对于一个设计模式我们关

简单谈一谈Java内部类的使用原因

使用内部类的原因 学习总得知其所以然,前面的一篇文章中我有提到过关于java内部类的几种用法以及一些示例,但是不明白内部类具体可以做什么,显然学习起来很渺茫,今天的文章简单说一说使用内部类的几个原因,为了可读性更好,示例都极大的简化了,希望能给初学者一些帮助 (一) 封装性 作为一个类的编写者,我们很显然需要对这个类的使用访问者的访问权限做出一定的限制,我们需要将一些我们不愿意让别人看到的操作隐藏起来, 如果我们的内部类不想轻易被任何人访问,可以选择使用private修饰内部类,这样我们就无法通

如何才能够系统地学习Java并发技术?

Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中涉及到的技术原理十分丰富.为了更好地把并发知识形成一个体系,也鉴于本人目前也没有能力写出这类文章,于是参考几位并发编程方面专家的博客和书籍,做一个简单的整理. 首先说一下我学习Java并发编程的一些方法吧.大概分为这几步: 1.先学会最基础的Java多线程编程,Thread类的使用,线程通信的一些方

Java内部类

本文是<Java核心技术 卷1>中第六章接口与内部类中关于内部类的阅读总结. Java中的内部类(inner class)是定义在另一个类内部的类.那么内部类有什么用呢?这里主要由三个内部类存在的原因: 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据.即,如果类A中定义了类B,那么类B可以访问类A中的数据,甚至是私有数据,但类A不能访问类B中的私有数据: 内部类可以对同一个包中的其他类隐藏起来.在一个包中,定义一个类时,即使不加上访问权限关键词,这个类也是包内其他类可访问的,不

(转)java缓存技术,记录

http://blog.csdn.net/madun/article/details/8569860 最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇,暂作保存,后面如果有用到可以参考.此为转贴,帖子来处:http://cogipard.info/articles/cache-static-files-with-jnotify-and-ehcache 介绍 JNotify:http://jnotify.sourceforge.net/,通过JNI

Java内部类:局部内部类(三)

Java内部类分为4个部分进行阐述,分别为概览.成员内部类.局部内部类和匿名内部类. 在本文中是Java内部类的局部内部类,主要讲局部内部类的概念和在使用局部内部的过程中,需要注意的一个细节. 1.局部内部类的概念 在一个类的方法内部定义另外一个类,那么另外一个类就称作为局部内部类. class OutterClass { void test() { class InnerClass//局部内部类 { } } } 在上述代码中,InnerClass定义在OutterClass的test方法的内部