Java内部类

一、对象的初始化方法

1.提供 get set 方法
//1.提供 get set 方法
class Person{
    private int age;
    private String name;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }

/*    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }*/
}


public class ObjectInit {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(18);
        person.setName("qzz");
        person.setSex("man");
        // System.out.println(person);没有生成toString打印的是地址
        System.out.println(person.getAge());
        System.out.println(person.getName());
        System.out.println(person.getSex());
    }
}

 

2.通过合适的构造函数进行初始化(系统本身会自动生成无参数的构造函数)

2.1(对象的创建要分为哪几部)

a.为对象创个内存

b.调用合适的构造函数

带有参数的构造函数

this 指向的是当前对象的内存

//2.通过合适的构造函数进行初始化
// (系统本身会自动生成无参数的构造函数)
/*    2.1(对象的创建要分为哪几部)

            a.为对象创个内存

            b.调用合适的构造函数*/
//定义类Person1   自己不添加任何无参或有参数构造方法
class Person1{
    private int age;
    private String name;
    private String sex;

}
//定义类Person2   自己添加无参的构造方法
class Person2{
    private int age;
    private String name;
    private String sex;

    public Person2(){
        System.out.println("无参构造方法被调用");
    }
}

//定义类Person3   有参数的构造方法
class Person3{
    private int age;
    private String name;
    private String sex;

    public Person3(String name, String sex, int age ){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}
//定义类Person4   自己添加无参的构造方法,和有参数的构造方法
class Person4{
    private int age;
    private String name;
    private String sex;


    //不带参数的构造函数,可以被重载
    public Person4(){
        System.out.println("无参构造方法被调用");
    }

    //带参数对的构造函数
    public Person4(String name, String sex, int age ){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public String getSex() {
        return sex;
    }
    public int getAge(){
        return age;
    }

}


public class ObjectInit_2 {
    public static void main(String[] args) {
        //Person1 person1 = new Person1();//编译通过;①实例化Person对象    ②自动调用构造方法Person( )

        //Person2 person2 = new Person2();//编译通过;打印: 无参构造方法被调用


        // 这样写,编译器会报错,原因是无参构造方法被有参构造方法覆盖,编译器不能提供无参构造方法
        //Person3 person3 = new Person3();

        //Person4 person4 = new Person4();//编译通过;打印: 无参构造方法被调用

        /*Person4 person4 = new Person4("qzz", "man", 18);
        System.out.println(person4.getAge());
        System.out.println(person4.getName());
        System.out.println(person4.getSex());*/

    }
}


 

2.1this 在无参数构造函数的用法
//this 在无参数构造函数的用法
class Person5{
    private int age;
    private String name;
    private String sex;


    private static final int COUNT = 10;//方法区

    public Person5() {//不带参数的构造函数  构造函数可以被重载
        this("songjaing","man",999);//调用带有三个参数的构造函数
         //this("songjaing","man");
        System.out.println("Person()");

        //count++;
      /*  this.age = 10;//this:指向当前对象的内存
        this.sex = "man";
        this.name = "caocao";*/

    }
    public Person5(String name,String sex,int age) {
        System.out.println("Person(name,sex,age)");
        this.age = age;//this:指向当前对象的内存
        this.sex = sex;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person5{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}


public class ObjectInit_2_1 {
    public static void main(String[] args) {
        Person5 person5 = new Person5();
        System.out.println( person5 );
    }
}

 

3.静态块初始化

(类名去调用)

static 所修饰的方法或者数据成员不依赖于对象

static{

}

和实例块初始化

{
this.naem = “ddd”
this.sex = “men”
}

//对象的初始化顺序???
//
//
//先静态块初始化(当类里面有 实例成员 和 实例代码块时,同等级别的执行顺序按照他们的顺序来执行)
//
//然后实例代码块初始化
//
//再然后构造函数初始化
class Person6 {
    private int age;//数据
    private String name;
    private String sex;
    private  static  int count; //???????

    {
        this.name = "gaobo";
        this.sex = "superman";
        this.age = 18;
        System.out.println("instance {} init");//实例块初始化
    }

    public Person6() {
        System.out.println("Person().constrcutor");
    }

    static {//static所修饰的方法或者数据成员不依赖于对象
        count = 10;
        //this.name = "gaobo";
        System.out.println("static {} init");
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}
public class ObjectInit_3 {
    public static void main(String[] args) {
        Person6 person6 = new Person6();
        System.out.println(person6);
       /* System.out.println("----------------------");
        Person6 person7 = new Person6(); //   这几句代码验证了*不管多少个对象,静态代码块只初始化一次 static代码块只出现一次*/
    }

}


//输出:
/*
static {} init
instance {} init
Person().constrcutor
Person{age=18, name='gaobo', sex='superman'}
----------------------
instance {} init
Person().constrcutor

Process finished with exit code 0

*/

 
4.对象的初始化顺序(上面的代码)

先静态块初始化(当类里面有 实例成员 和 实例代码块时,同等级别的执行顺序按照他们的顺序来执行)

然后实例代码块初始化

再然后构造函数初始化

*不管多少个对象,静态代码块只初始化一次


 

二、内部类

在这里插入图片描述

内部类:定义在类结构中的另一个类:类中的定义的成员:

字段

方法

内部类


为什么使用内部类:

1):增强封装,把内部类隐藏在外部类之内,不许其他类访问内部类。

2):内部类能提高代码的可读性和可维护性,把小型类嵌入到外部类中结构上代码更靠近。

3):内部类可以直接访问外部类的成员。

在这里插入图片描述

根据使用不同的修饰符或者定位的位置不同,分成四种:

四种内部类:

① 实例内部类: 内部类没有使用static修饰.

② 静态内部类: 内部类使用了static修饰.

③ 局部内部类: 在方法中定义的内部类.

④ 匿名内部类适合于仅使用一次使用的类,属于局部内部类的特殊情况:

外部类的访问修饰符:要么使用public,要么就缺省.

内部类看做是外部类的一个成员,好比字段,那么内部类可以使用public/缺省/protected/private修饰.

还可以是static修饰.


 

1.实例内部类:

实例内部类(没有static修饰)
面试问题1.实例内部类是否有额外的开销(有)???实例内部类是否有拥有外部内的对象(有)
面试问题2.实例内部类当中是否可以有静态数据成员(有)但是只能是在编译期间确定的值,可以 是static但是必须是final所修饰

没有使用static修饰内部类,说明内部类属于外部类的对象,不属于外部类本身.

特点:

1:创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象时,一定存在外部类对象). Outter.Inner in = new Outter().new Inner();

2:实例内部类的实例自动持有外部类的实例的引用,内部类可以直接访问外部类成员.

3:外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问.

4:实例内部类中不能定义静态成员,只能定义实例成员.

5:如果实例内部类和外部类存在同名的字段或方法abc,那么在内部类中:

  • this.abc:表示访问内部类成员.
  • 外部类.this.abc:表示访问外部类成员.
class OuterClass1{
    String name = "Outer.name";
    public int data1;
    private int data2;
    private static int data3;

    {
        data1 = 999;
        data2 = 888;
        data3 = 777;
    }



    public void ooxx(){
        System.out.println(this.new InnerClass().age);
    }
    //实例内部类
    class InnerClass{
        int age = 17;
        String name = "Inner.name";

        private int data3 = 100;
        public int data5 = 10;
        //private static  int DATA4 = 1000;error
        private static final int DATA4 = 1000;
        //private static final int DATA4 = data5;error


        public void test(){
            String name = "local.name";
            System.out.println(name);//访问内部类方法中的的name//如果方法中没有,访问的是内部类的name
            System.out.println(this.name);//访问内部类的name
            System.out.println(OuterClass1.this.name);//访问外部类的name
        }

        public void test2(){
            System.out.println(data1);//999
            System.out.println(data2);//888    OuterClass2.this.
            System.out.println(this.data3);//100
            System.out.println(OuterClass1.this.data3);//777
            System.out.println("InnerClass2().test2()");
        }
    }
}
public class TestInnerClassDemo2 {
    public static void main(String[] args) {
        OuterClass1 outerClass = new OuterClass1();
        //外部类名.内部类名    引用名 =  外部类对象.new 内部类();
        OuterClass1.InnerClass innerClass1 = outerClass.new InnerClass();
        innerClass1.test();
        System.out.println("-------------------");
        innerClass1.test2();
    }
}

 

2.静态内部类

使用static修饰的内部类.特点:

1):静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例. Outter.Inner in = new Outter.Inner();

2):静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.

3):在静态内部类中可以定义静态成员和实例成员.

4):测试类可以通过完整的类名直接访问静态内部类的静态成员.

面试问题

1.静态内部类如何访问外部类的非静态数据成员(静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.)

2.静态内部类是否拥有外部类对对象( 不拥有:静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例)

class OuterClass {
    public int data1 = 1;
    private int data2 = 2;
    private static int data3 = 3;

    public OuterClass() {
        System.out.println("OuterClass() init");
    }
    static class InnerClass {
        public int data4 = 4;
        OuterClass outr;
        public InnerClass(OuterClass outr) {
            this.outr = outr;
            System.out.println("InnerClass()init");
        }
        public void test2() {
            System.out.println(data3);
            System.out.println(data4);
            System.out.println(outr.data2);//如何访问外部类的非静态数据成员
            System.out.println(new OuterClass().data1);// ????
            System.out.println("InnerClass().test2()");
        }
    }

}
public class TestInnerClassDemo1 {
    public static void main(String[] args) {
        //InnerClass innerClass = new InnerClass();(错误)
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass1 = new OuterClass.InnerClass(outerClass);
        System.out.println("-----------------------");
        innerClass1.test2();
    }
}


 

3.局部内部类

局部内部类(打死都不用):

在方法中定义的内部类,其可见范围是当前方法和局部变量是同一个级别.

1):不能使用public,private,protected,static修饰符.

2):局部内部类只能在当前方法中使用.

3):局部内部类和实例内部类一样,不能包含静态成员.

4):局部内部类和实例内部类,可以访问外部类的所有成员.

5):局部内部类访问的局部变量必须使用final修饰(在Java8中是自动隐式加上final,但是依然是常量,不能改变值).

原因:如果当前方法不是main方法,那么当前方法调用完毕之后,当前方法的栈帧被销毁,方法内部的局部变量的空间全部销毁.

然后局部内部类是定义在方法中的,而且在方法中会创建局部内部类对象,而局部内部类会去访问局部变量,当当前方法被销毁的时候,对象还在堆内存,依然持有对局部变量的引用,但是方法被销毁的时候局部变量以及被销毁了.

此时出现:在堆内存中,一个对象引用着一个不存在的数据. 为了避免该问题,我们使用final修饰局部变量,从而变成常量,永驻内存空间,即使方法销毁之后,该局部变量也在内存中,对象可以继续持有.

在这里插入图片描述


 

4.匿名内部类

匿名内部类(Anonymous),是一个没有名称的局部内部类,适合只使用一次的类。

在开发中经常有这样的类,只需要定义一次,使用一次就可以丢弃了,此时:不应该白白定义在一个文件中.

在JavaSE/Android的事件处理中:不同的按钮点击之后,应该有不同的响应操作,首先使用匿名内部类.

特点:

1):匿名内部类本身没有构造器,但是会调用父类构造器.

2):匿名类尽管没有构造器,但是可以在匿名类中提供一段实例初始化代码块,JVM在调用父类构造器后,会执行该段代码.

3):内部类处理可以继承类之外,还可以实现接口.

格式:

new 父类构造器([实参列表]) 或 接口()

{

//匿名内部类的类体部分

}

注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口。

在这里插入图片描述

/**
 * 匿名内部类:
 *
 */
class OuterClass3 {
    public void sayHello() {
        System.out.println("hello");
    }
}


public class TestInnerClass3 {

    public static void test(OuterClass3 out3) {
        out3.sayHello();
    }

    public static void main(String[] args) {
        //第一种
        new OuterClass3() {
            public void sayHello() {
                System.out.println("main : hello");
            }
        }.sayHello();

        test(new OuterClass3());
    }
}
                                             2018.10.29/周一
                                             by 922
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值