匿名对象和内部类
匿名对象
匿名对象是指在创建对象的时,只有创建对象的语句,却没有把对象地址赋值给某个变量.
public class Person{ public void eat(){ System.out.println(""); }}
创建一个普通对象
Person p = new Person();
匿名对象
new Person();
特点
创建匿名对象直接使用,没有变量名.
new Person(),eat();
在只使用一次的情况下使用,因为每次new都会出来一个新的对象.
例如接受一次键盘输入:int number = new Scanner(system.in).nextInt();
但要多使用,因该为其指定引用变量
可以作为方法的接受参数和返回参数
Class Demo{Public static Person getPerson(){//普通方式//Person p = new Person();//return p;//匿名对象作为方法返回值return new Person();} public static void method(person){}}
Class Test{Public static void main (String[] args){//调用getperson方法得到person对象Person p = Demo.getPerson();//调用method方法Demo.method(p);//匿名对象作为方法接受参数Demo.method(new Person());}}
内部类的概述
将类写在其他类的内部,可以写在其他类的成员位置和局部位置,这时写在其他类内部的类就称为内部类,其他类被称为外部类
什么时候使用内部类
在描述事物的时候,若一个事物内部还包含其他可能包含的事物,比如在描述汽车的时候,汽车中还包含着发动机,这个时候就可以用内部类来描述
内部类的分类
根据定义的位置的方式不同可以分为4类
静态内部类
成员内部类
方法内部类
匿名内部类
静态内部类
和定义静态变量和静态方法一样,在类名前面加上static关键字,语法上静态类除了位置放在被的类内部以为,和独立类区别不大,可以有静态方法,静态变量,成员方法,成员变量,构造方法等
public class demo { private static int shared = 100; public static class StaticInner { public void innerMethod(){ System.out.println("inner " + shared); } } public void test(){ StaticInner si = new StaticInner(); si.innerMethod(); } }
注意:
与其他三种内部类相比,静态内部类与外部类的联系也不大,可以访问外部类的静态方法和静态变量,但不可以访问实例变量和方法.
静态内部类可以声明静态方法静态变量,而非静态内部类不可以声明静态变量和静态方法
public静态内部类可以被外部使用,只是需要通过"外部类.静态内部类"的方式使用,如下所示:
Outer.StaticInner si = new Outer.StaticInner();
si.innerMethod();
使用场景:
如果内部类与外部类关系密切有不依赖于外部类就可以考虑定义为静态内部类一个类内部,如果既要计算最大值,也要计算最小值,可以在一次遍历中将最大值和最小值都计算出来,但怎么返回呢?可以定义一个类Pair,包括最大值和最小值,但Pair这个名字太普遍,而且它主要是类内部使用的,就可以定义为一个静态内部类。
成员内部类:
定义在外部类的成员变量的位置,与外部类的成员变量相似可以使用成员变量的修饰符,可通过外部类对象进行访问,与静态内部类,相比少了static修饰,但有了很大的不同
定义方式
Class 外部类{Class 外部类{ }}
实例化内部类
外部类.内部类 变量名 = new 外部类().new外部类();
或者分开写
外部类 变量名1 = new 外部类
变量名.内部类 变量名2 = 变量名1.new 内部类
与静态不同,成员内部类总是与一个外部类的对象向连,外部类在使用的时候要内部类的方法就必须有一个该类的对象,因此,使用内部类就必须先有个外部类,在通过外部类去找到内部类,在调用内部类的方法.
class Body {//外部类,身体 private boolean life= true; //生命状态 public class Heart { //内部类,心脏 public void jump() { System.out.println("心脏噗通噗通的跳") System.out.println("生命状态" + life); //访问外部类成员变量 } }}
访问内部类
public static void main(String[] args) {//创建内部类对象 Body.Heart bh = new Body().new Heart();//调用内部类中的方法 bh.jump();}
内部类访问外部类
成员内部类可以无条件的访问外部类的所有成员属性和成员方法(包括private和static)毕竟内部类也是外部类的成员
当成员内部类和外部类有同名的成员,内部类的成员就会暂时将外部类给隐藏,这个时候需要以下的方式访问
外部类.this.成员变量(成员方法)
public class Outer { int i = 1; class Inner { int i = 2; public void inner(){ int i = 3; System.out.println(Outer.this.i); } }}
平常如果属性名不重复,那么我们在内部类中调用外部类的属性和方法时,前面就隐式的调用了Outer.this。
题
//要求:使用已知的变量,在控制台输出30,20,10。
class Outer { public int num = 10; class Inner { public int num = 20; public void show() { int num = 30; System.out.println(?); System.out.println(??); System.out.println(???); } } } class InnerClassTest { public static void main(String[] args) { Outer.Inner oi = new Outer().new Inner(); oi.show(); } }
答案:num、this.num、Outer.this.num
成员内部类的使用场景
如果内部类与外部类关系密切,且操作或依赖外部类实例变量和方法,则可以考虑定义为成员内部类。
外部类的一些方法的返回值可能是某个接口,为了返回这个接口,外部类方法可能使用内部类实现这个接口,这个内部类可以被设为private,对外完全隐藏。
局部内部类
局部内部类定义在一个方法或者一个作用域里面,他和成员内部类的区别在于仅限于在方法内或作用域呢,与访问方法的局部变量相似,可以通过调用方法进行访问.
定义格式
class 外部类 { 修饰符 返回值类型 方法名(参数) { class 内部类 { //其他代码 } } }
外部类访问局部内部类
在外部类方法中,创建局部内部类进行访问
定义类
class Party {//外部类,聚会
public void puffBall(){// 吹气球方法
class Ball {// 内部类,气球
public void puff(){
System.out.println("气球膨胀了");
}
}
//创建内部类对象,调用puff方法
new Ball().puff();
}
}
访问内部类
public static void main(String[] args) {
//创建外部类对象
Party p = new Party();
//调用外部类中的puffBall方法
p.puffBall();
}
局部内部类访问局部变量
局部变量要被final修饰才能被内部类访问
jdk1.8以后已经不需要在内部类引用局部变量时加final关键字了
使用场景
方法内部类都可以用成员内部类代替,至于方法参数,也可以作为参数传递给成员内部类。不过,如果类只在某个方法内被使用,使用方法内部类,可以实现更好的封装。
匿名内部类
和匿名对象一个道理.
定义格式:
new 父类(参数列表) {
//匿名内部类实现部分
}
new 父接口() {
//匿名内部类实现部分
}
前提:必须有接口或者继承,匿名内部类的本质就是实现了接口或者继承了某个子类的匿名对象
例子
定义一个接口
public interface Smoking{
Public adstract void smoking();
}
普通做法实现类,实现接口,重写抽象方法,创建实现类对象
XXX x = new XXX();
x.smoking();
Smoking s = new XXX();
s.smoking();
匿名内部类 简化问题 定义实现类,重写方法,建立实现类对象,合为一步完成
public class Test{
public static void main(String[] args){
new Smoking (){
public void smoking() {
System.out.println(“人在吸烟”;)
}
}.smoking;
}
}
使用匿名内部类
定义实现类,重写方法,创建实现类对象,一步搞定
格式:
new 接口或者父类(){
重写抽象方法
};
从 new开始,到分号结束
创建了接口的实现类的对象
例子
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
public class Test2 {
public static void main(String[] args) {
Animal a= new Animal(){
public void eat(){
System.out.println("在吃饭");
}
public void sleep(){
System.out.println("在睡觉");
}
};
a.eat();
a.sleep();
}
}
注意
匿名内部类只能被用一次,用来创建一个对象,由于没有名字,所以也就没有构造方法,但可以根据参数列表,调用对应的父类构造方法.可以定义实例变量和方法,可以有初始化代码块,初始化代码块可以起到构造方法的作用.
与方法内部类一样,匿名内部类也可以访问外部类的所有变量和方法,可以访问方法中的final参数和局部变量
使用场景
匿名内部类能做的方法内部类都能做,但如果对象只会创建一次,就可以使用匿名内部类,代码上的书写更简洁.
用于回调
题
按照要求,补齐代码
interface Inter { void show(); }
class Outer {
//补齐代码
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
interface Inter { void show(); }
class Outer {
//补齐代码
public static Inter method(){
return new Inter(){
void show(){
System.out.println("HelloWorld");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
为什么要有内部类呢
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
成员内部类继承问题
一般来说成员内部类是很少用来继承的,但如果真要继承
1)成员内部类的引用方式必须为 Outter.Inner.
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
class WithInner {
class Inner{
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}
共同学习,写下你的评论
评论加载中...
作者其他优质文章