Java基础之内部类

先举个简单例子引出内部类:

当描述事务时,一个事务的内部还有事务,该事务用内部类来表示,该内部事务需要用到外部事务的内容。

例如:一个人体,它里面有各种器官:胃,肝等,拿胃来说,它要用到人体的食道,那么我们就可以把胃定义成内部类
 

public class Body {

    private String shidao = "shidao";

    /**
     * 1胃是body私有的,不能让其它人直接访问,可以提供一个方法给外面
     * 2这也体现了面向对象的设计思想
     */
    private class Wei {
        private void work() {
            System.out.println("i am work through" + Body.this.shidao);
        }
    }

    public Wei showWei() {
        return new Wei();
    }

}

基本概念:

  • 将内部类当做是一个类中的方法,它就享有一个方法该有的东西,比如四个权限修饰符,比如局部内部类不能含有权限修饰符等
  • 内部类分为成员内部类和局部内部类,成员内部类分为:静态内部类和实例内部类;局部内部类:class修饰和匿名内部类(就是直接new一个类或接口)
  • 只有当类被abstract修饰时候,类中的方法才能用abstract;这个类可以是任何类型的类(除了匿名内部类)
  • 内部类可以是接口和枚举,他们一直都是静态的,我们可以用他们来把一些字段归类,然后其它地方可以使用
  • 实例内部类可以访问外部类的所有变量和方法,它自己不能含有任何static的东西,这与方法一样(实例方法不可能含有静态东西)
  • 内部类如果定义了static成员,那么该类必定是静态内部类
  • 内部类表达过程中最好把从属关系表达出来,这样有助于理解:其它地方要使用对象a的实例内部类Inner:先new:a.new Inner()

下图是内部类特点:

public class Outer {
    private String name="tgm";
    //可以有四种权限修饰符修饰,
    public static class In1{}
    public class In2{int in2Num=2;}
    private abstract class In3{ public abstract void callMe();}
    private class In4{
        private String name="in4";
        private void doSay(){
            String name="doSay";
            //内部类访问外部类东西原因就是Outer.this访问自己的就是this.
            System.out.println(this.name+Outer.this.name+name);
        }
    }
    private void userIn(){
        //外部类要访问成员内部内中的东西就需要先实例化它
        In2 in2=new In2();
        //in2Num尽管是private的,但是它是在Outer类中,所以还是能够被访问
        System.out.println(in2.in2Num);
    }
}

public class TestClass {

    public String name;

    public static void main(String[] args) {
        //实例内部类的创建方式
        Outer outer=new Outer();
        Outer.In2 in2= outer.new In2();
        //因为in2Num权限修饰符原因,不在同包中的类不能访问
        System.out.println(in2.in2Num);

        //静态内部类的创建
        Outer.In1 in1=new Outer.In1();
        System.out.println();
    }

}

内部类的用处举例:

  1. 有时候我们会有Constant这样的存储静态变量类,而我们可以使用内部接口或者枚举来分类:
    public class Constant {
        
        public static final String CURRENT_USER = "currentUser";
    
        public enum VerifyType {
            USERNAME("username"),
            EMAIL("email");
            VerifyType(String str){
                this.str=str;
            }
            private String str;
            public String getStr(){
                return this.str;
            }
        }
        public interface VerifyMsg{
            //接口里面的字段默认是public static final 修饰的编译常量
            public static final String USERNAME_EXIST = "用户名已经存在";
            String USERNAME_NOT_EXIST = "用户名不存在";
            String EMAIL_EXIST = "Email已经存在";
            String ERROR_TYPE = "无效的验证类型";
        }
    }

    使用方式:

    Constant.VerifyType.USERNAME.getStr()
    Constant.VerifyMsg.EMAIL_EXIST
    
  2. 高级用法,使用内部类作为字段来保存某个方法,然后在其它地方使用:
    public class Dog {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.run();
        }
        public void run() {
            DogAb dogAb=new DogAb();
            try{
                //这里就是引用类型参数传递,所以我们用了内部类来作为参数,用它来保存
                calculate("good",dogAb);
            }finally {
                if(dogAb.callRun!=null){
                    dogAb.callRun.justDo();
                }
            }
        }
        public void calculate(String type,DogAb dogAb) {
            Integer num=1;
            if(type.equals("good")){
                num+=1;
            }
            if(type.equals("bad")){
                num-=1;
            }
            //匿名内部类使用的都是final字段,所以要重新赋值
            Integer finalNum = num;
            dogAb.callRun = dogAb.new CallRun(){//匿名内部类可以复写所有方法
                @Override
                void doSomething() {
                    sendMsg(finalNum,"http://baga:8903/kk");
                }
            };
    
        }
        public void sendMsg(int num,String url){
            //这里面就需要使用上面的num,条件要求这个方法要在其它地方使用,所以这里怎么办呢?因为我们一般是直接调用方法
            //解决办法是:我们先要把这个方法存起来,其它方法要用的时候再调用,怎么实现?就要用到线程和内部类
            System.out.println("num is:"+num+"\nurl is:"+url);
        }
    }
    
    public class DogAb {
        //这里我们必须使用一个内部类,然后把这个类作为一个字段引用
        //因为在我们的实际使用中牵扯到了引用类型的参数传递问题,
        //引用类型传递的是指向对象的栈地址,这是一个全新的变量B,
        //重新给它new对象并没有改变到A的指向
        CallRun callRun;
    
        public class CallRun {
            void doSomething() {
    
            }
    
            public void justDo() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        doSomething();
                    }
                }).start();
            }
        }
    }
    

     

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值