常用的引用类型用法总结
实际的开发中,引用类型的使用非常重要,也是非常普遍的。我们可以在理解基本类型的使用方式基础上,进一步去掌握引用类型的使用方式。基本类型可以作为成员变量、作为方法的参数、作为方法的返回值,那么当然引用类型也是可以的。
类名作为形参和返回值
- 类名作为方法的形参: 方法的形参是类名,其实需要的是该类的对象.实际传递的是该对象的【地址值】
- 类名作为方法的返回值:方法的返回值是类名,其实返回的是该类的对象。 实际传递的,也是该对象的【地址值】
抽象类作为形参和返回值
- 方法的形参是抽象类名:其实需要的是该抽象类的子类对象
- 方法的返回值是抽象类名:其实返回的是该抽象类的子类对象
接口名作为形参和返回值
- 方法的形参是接口名:其实需要的是该接口的实现类对象
- 方法的返回值是接口名:其实返回的是该接口的实现类对象
数组作为方法参数和返回值
- 数组作为方法参数传递,传递的参数是数组内存的地址。
- 数组作为方法的返回值,返回的是数组的内存地址
总结:
方法的参数为基本类型时,传递的是数据值. 方法的参数为引用类型时,传递的是地址值.
内部类
概念:将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。成员内部类 :定义在类中方法外的类 局部内部类:定义在类中方法里的类。
成员内部类的定义格式:
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
示例
package demo03; public class Outer { private int num = 10; public class Inner { public void show() { // 内部类可以直接访问外部类的成员,包括私有 System.out.println(num); } } public void method() { // 外部类要访问内部类的成员,必须创建对象 Inner i = new Inner(); i.show(); } }
成员内部类
- 定义位置:在类中方法,跟成员变量是一个位置
外界创建成员内部类
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
举例:
Outer.Inner oi = new Outer().new Inner();
成员内部类作为类的成员的角色(看成一个成员变量):
- 和外部类不同,Inner class还可以声明为private或protected;
- 可以调用外部类的结构
- Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;
成员内部类作为类的角色(看成一个类):
- 可以在内部定义属性、方法、构造器等结构
- 可以声明为abstract类 ,因此可以被其它的内部类继承
- 可以声明为final的
- 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)
小结
- 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
- 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
- 成员内部类可以直接使用外部类的所有成员,包括私有的数据
- 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
局部内部类
- 定义位置:局部内部类是在方法中定义的类
格式:
局部内部类使用方式
- 局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
局部内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
- 局部内部类可以使用外部类的成员,包括私有的。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
- 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
- 局部内部类不能使用static修饰,因此也不能包含静态成员
示例
package demo03; class Outer { private int num = 10; public void method() { int num2 = 20; class Inner {//局部内部类 public void show() { //直接访问外部类的成员,也可以访问方法内的局部变量 System.out.println(num); System.out.println(num2); } } //局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用 Inner i = new Inner(); i.show(); } }
匿名内部类
匿名内部类属于局部内部类其中的一种。匿名内部类 :是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,
- 定义子类
- 重写接口中的方法
- 创建子类对象
- 调用重写后的方法
我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。
前提:
- 匿名内部类必须继承一个父类或者实现一个父接口。
格式
对格式“new 接口名称() {...}”进行解析:
- new代表创建对象的动作
- 接口名称就是匿名内部类需要实现哪个接口
- {...}这才是匿名内部类的内容
匿名内部类的特点
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
匿名内部类在开发中的使用
- 当发现某个方法需要,接口或抽象类的子类对象,我们就可以传递一个匿名内部类过去,来简化传统的代码
以接口举例:
定义接口
package demo04; /* 飞行接口 */ public abstract class FlyAble { public abstract void fly(); }
创建匿名内部类,并调用:
package demo04; public class InnerDemoTest { public static void main(String[] args) { /* 1.等号右边:是匿名内部类,定义并创建该接口的子类对象 2.等号左边:是多态赋值,接口类型引用指向子类对象 */ } FlyAble f = new FlyAble() { public void fly() { System.out.println("我飞了~~~"); } };//调用 fly方法,执行重写后的方法 f.fly(); }
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
package demo04; public class Demo { public static void main(String[] args) { /*创建匿名内部类,直接传递给showFly(FlyAble f) */ showFly(new FlyAble() { public void fly() { System.out.println("我飞了~~~"); } }); } public static void showFly(FlyAble f) { f.fly(); } }
另外还要注意几点问题:
- 匿名内部类,在【创建对象】的时候,只能使用唯一一次。如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。
- 匿名对象,在【调用方法】的时候,只能调用唯一一次。如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
- 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】。强调:匿名内部类和匿名对象不是一回事!!!