侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

内部类和Object类

coydone
2021-01-17 / 0 评论 / 0 点赞 / 350 阅读 / 5,550 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-01,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

内部类

内部类(innerclasses)是一类特殊的类,指的是定义在一个类的内部的类。实际开发中,为了方便的使用外部类的相关属性和方法,这个时候我们通常会定义一个内部类。

位置:把一个类定义到另一个类中,那么内部的类就是内部类。

注意:内部类不能直接创建。

创建内部类的语法:外部类.内部类 变量名 = new 外部类对象.new内部类对象

内部类的外部类的方法如果想要访问内部类的方法,必须创建内部类的对象,根据内部类的对象来访问。

内部类可以使用public、default、protected、private以及static修饰。而外部顶级类只能使用public和default修饰。

内部类只是一个编译时的概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outter的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outter.class和Outter$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。

内部类的编译后的class文件:

内部类的作用

内部类提供了更好的封装。只能让外部类直接访问不允许同一个包中的其他类直接访问。

内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。

内部类的分类

非静态内部类

非静态内部类,外部类里使用非静态内部类和平时使用其他类没什么不同。

  • 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类。对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。

  • 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。

  • 非静态内部类不能有静态方法、静态属性和静态初始化块。

  • 成员变量访问要点:

    • 内部类里方法的局部变量:变量名。

    • 内部类属性:this.变量名。

    • 外部类属性:外部类名.this.变量名。

class Outter {
    int num = 20;

    public void outMethod() {
        System.out.println("我是外部的类的方法");
    }

    class Inner {
        int innerNum;
        int num = 10;

        public void inMethod() {
            //当外部类和内部类的属性发生重合时,可以使用Outter.this.成员名
            System.out.println(Outter.this.num);
        }
    }
}

public class TestInner {
    public static void main(String[] args) {
        //创建内部类的对象  外部类.内部类 变量名 = new 外部类对象.new内部类对象
        Outter.Inner inner = new Outter().new Inner();
        inner.innerNum = 13;
        inner.inMethod();//我是内部的类的方法
    }
}

静态内部类

静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。静态内部类看做外部类的一个静态成员。

class Outer {
    private int a = 10;
    private static int b = 20;

    //相当于外部类的一个静态成员
    static class Inner {
        public void test() {
//            System.out.println(a);//静态内部类不能访问外部类的普通属性
            System.out.println(b);//静态内部类可以访问外部类的静态属性
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //通过 new 外部类名.内部类名() 创建内部类对象
        Outer.Inner inner = new Outer.Inner();
        inner.test();
    }
}

匿名内部类

什么是匿名类:没有名字的类,这种类需要在接口上实现。适合只需要使用一次的类。

匿名类和匿名内部类都需要接口或者抽象类的支持。

创建一个匿名的类的对象这个类的对象实现OuterInter的接口,在大括号中实现接口中的方法,方法调用完毕后就会被垃圾回收。

接口中的匿名内部类

interface Outter {
    public void outMethod();
}

class OutterImpl implements Outter {
    public void outMethod() {
    }
}

public class TestInner {
    public static void main(String[] args) {
        Outter outter = new OutterImpl();
        outter.outMethod();

        //创建的不是接口本身,new Outter() 后面的大括号就是一个匿名内部类,
        // 实现了Outter接口
        Outter o = new Outter() {
            @Override
            public void outMethod() {
                System.out.println("我是匿名内部类的方法");
            }
        };
        o.outMethod();
    }
    //我是匿名内部类的方法
}

抽象类中的匿名内部类

abstract class Outter{
    public abstract void outMethod();
}
public class TestInner{
    public static void main(String[] args){
        //创建的不是接口本身,new Outter() 后面的大括号就是一个匿名内部类,
        // 实现了Outter接口
       Outter o = new Outter() {
           @Override
           public void outMethod() {
               System.out.println("我是匿名内部类的方法");
           }
       };
       o.outMethod();
    }
    //我是匿名内部类的方法
}

局部内部类

定义在方法内部的,作用域只限于本方法,称为局部内部类。

局部内部类的的使用主要是用来解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就会失效。局部内部类在实际开发中应用很少。

//方法中的内部类
public class Test {
    public void show() {
        //作用域仅限于该方法
        class inner {
            public void fun() {
                System.out.println("局部内部类");
            }
        }
        new inner().fun();
    }
    public static void main(String[] args) {
        new Test().show();
    }
}

Object

Object概述

Object是所有类的根类,所有的类都是直接或者间接的去继承Object类。

类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

在定义一个类时,没有使用extends关键字,也就是没有显式地继承某个类,那么这个类直接继承Object类。所有的对象都继承这个类的方法。

基本方法

toString():返回当前对象本身的有关信息,返回字符串对象。通常,toString() 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。

Object中的toString()的实现:

Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于: 获得类的名称“@”,getClass().getName() + '@' + Integer.toHexString(hashCode())

public class Test{
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(o.toString());
    }
}//java.lang.Object@1540e19d
public class Test{
    private String name = "张三";
    private  int age  = 10;

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

    public static void main(String[] args) {
        Test t=new Test();
        System.out.println(t.toString());
    }
}//name='张三', age=10

getClass():getClass()返回值是Class<T>(类的类对象),与反射有关。通过getClass().getName()获得对象的类名。

hashCode():由 Object 类定义的 hashCode() 方法确实会针对不同的对象返回不同的整数。

finalize():用于垃圾回收,我们不用手动的去调用,由JVM来调用,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

**equals(Object obj),返回值为布尔类型,**用于比较两个对象是否相等。

public class Test {
    public static void main(String[] args) {
        //1. 创建Object类型的对象
        Object obj1 = new Object();
        Object obj2 = new Object();

        //2. 测试Object类中的成员方法
        //2.1 hashCode:不同对象的哈希码值一般不同
        int code1 = obj1.hashCode();
        int code2 = obj2.hashCode();
        System.out.println(code1);//356573597
        System.out.println(code2);//1735600054
         
        //2.2 Class<?> getClass():一个类只有一个字节码对象。
        Class cls1 = obj1.getClass();
        Class cls2 = obj2.getClass();
        System.out.println(cls1);//class java.lang.Object
        System.out.println(cls2);//class java.lang.Object
         
        //2.3 String toString():返回对象的字符串形式,默认返回的是地址值,不同的对象有不同的返回值
        //地址值的组成:全类名@该对象的哈希码的无符号十六进制形式
        String s1 = obj1.toString();
        String s2 = obj2.toString();
        System.out.println(s1);//java.lang.Object@1540e19d
        System.out.println(s2);//java.lang.Object@677327b6
         
        //2.4 boolean equals():比较两个对象是否相等,默认比较地址值(无意义),子类一般会重写。
        boolean b = obj1.equals(obj2);
        System.out.println(b);//false
    }
}

对象的克隆

将一个对象复制一份,称为对象的克隆技术。

在object类中存在一个clone()方法:protected Object clone() throws CloneNotSupportedException

如果某个类的对象要想被克隆,则对象所在的类必须实现Cloneable接口。此接口没有定义任何方法,是一个标记接口。

对象克隆的应用场景是需要创建一组细粒度重复使用的对象时,使用克隆方式可能比直接创建对象的效率要高得多。

public class User implements Cloneable {
    private String name;
    private Integer age;
	//省略构造方法()、getter()、setter()、toString()

    //重写Object中的clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test {
    public static void main(String[] args) {
        User user = new User("Tom",20);
        try {
            User clone = (User) user.clone();
            System.out.println(user);
            System.out.println(clone);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
0

评论区