一、匿名对象
语法:只创建对象,没有对象引用去接收;
使用:匿名对象也是对象,和普通对象一样具有对象该有的功能;
匿名对象只能使用一次,调用方法也只能调用一次。就算下一次使用同名的匿名对象他也是新的对象;
匿名对象只在在堆内存中开辟空间,因为没有对象引用就不在栈内存中开辟空间了;
package 匿名对象;
public class Demo01Anonymous {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Demo01Anonymous da = new Demo01Anonymous();//正常创建对象
da.setName("Gallagher");
System.out.println(da.getName());
new Demo01Anonymous();//创建匿名对象
new Demo01Anonymous().setName("Noob");
System.out.println(new Demo01Anonymous().getName());
}
}
二、内部类:将一个类定义到另一个类里面;
内部类共同点:
- 内部类可以无条件访问外部类的属性和方法,如果内部类有和外部类同名的方法或者属性就必须使用"外部类名.this.外部类方法名"进行调用,this为关键字,表示对外部类的引用;就算你访内部类的方法或者属性也要加上this用以区分"this.内部类方法名"
- 外部类如果要访问内部类的属性或者方法则需要创建一个内部类的对象,然后通过该对象去访问内部类的属性或者方法
- 当内部类被private修饰,那么就仅外部类可访问
- 成员内部类:就相当于新建一个位于成员位置的类,为最普通的一种:
如果内部类有和外部类同名的方法或者属性就必须使用"外部类名.this.外部类方法名"进行调用,就算你访内部类的方法或者属性也要加上this用以区分"this.内部类方法名"
注意!!! 非静态内部类中不可以定义static修饰的属性和方法:
- static修饰方法、成员变量属于类自己,并不属于特定的某个对象。所以我们可以直接通过类名.方法或者类名.属性去访问static修饰的方法或属性,可以不用new一个class出来。通过new出来的对象就是特定的对象;所以说不能在静态方法内使用非静态的成员变量,因为这个成员变量不是类自己,而是某一个对象的,不能确定在使用这个成员变量的时候这个对象是否存在;
- 在这里:静态属性和代码块会先加载,所以说,非静态内部类中的静态属性也要优于这个内部类加载,但这个时候这个内部类都还没有初始化。这个就是存在问题的;只要是非静态成员变量(这里的非静态内部类在外部类中就相当于一个非静态成员变量),就需要依赖具体的对象,这个时候如果在非静态内部类里面声明静态属性就有问题;
package 匿名内部类;
class Demo02Test{
private String name = "外部类名";
private int age = 24;
private void methodOut() {
System.out.println("外部类方法");
}
class Inner{
public String name = "内部类名";
private int age = 25;
private void methodIn() {
System.out.println("内部类方法访问外部属性用外部类名.this.属性 :" + Demo02Test.this.age + Demo02Test.this.name+" "
+"内部类访问内部类属性用this.内部类属性 :"+this.age+ this.name);
}
}
public static void main(String[] args) {
Demo02Test dt = new Demo02Test();
System.out.println(dt.name + dt.age);
/* Inner in = new Demo02Test().new Inner(); 等同于后面*/ Inner in = dt.new Inner();
System.out.println(in.age + in.name);
in.methodIn();
}
}
结果输出为:
外部类名24
25内部类名
内部类方法访问外部属性用外部类名.this.属性 :24外部类名 内部类访问内部类属性用this.内部类属性 :25内部类名
- 局部内部类
注意:
- 局部内部类不能被public、private、static修饰
- 外部类中不能创建内部类的实例
- 创建局部内部类的实例只能在他的方法中
- 内部类访问包含他的方法中的变量必须有final修饰
为什么呢: 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用。---->局部内部类的生命周期比局部变量的生命周期长
- 外部类不能访问局部内部类,只能在方法体中访问局部内部类,且访问必须在内部类定义之后。
package 匿名内部类;
/*这里的MZ如果全部换为name的话,该如何访问呢??好像不能访问,有知道的解答一下:问题就是局部内部类怎么访问其外部方法的同名变量*/
class Demo02Test{
private String MZ = "A";
private void methodOuter() {
String MZ = "B"; //前面默认加上final
//String MZ = "DD"; //前面我虽然没有写final,jdk8默认加上了final。不能做出修改
class Inner{ //这里如果你加了public、private、static修饰,那么会提示:Remove invalid modifiers
private String name = "C";
private void methodInner() {
String name ="D";
System.out.println("输出局部内部类方法中的名:"+ name);
System.out.println("输出局部内部类定义中的名:" + this.name);
System.out.println("输出外部类定义的名字:" + MZ);
System.out.println("输出包含内部类的方法中定义的名字" + Demo02Test.this.MZ);
}
}
//在他的方法中创建内部类对象
Inner in = new Inner();
in.methodInner();
System.out.println("我要访问包含内部类的方法中的属性值:" + Demo02Test.this.MZ);
System.out.println("我要访问外部类的属性值:" + new Demo02Test().MZ);
}
//这里我在外部类中创建内部类的实例,是会提示报错的
/*
* Inner in = new Inner();
* System.out.println(name);
*/
public static void main(String[] args) {
Demo02Test dt = new Demo02Test();
dt.methodOuter();
}
}
执行结果为:
输出局部内部类方法中的名:D
输出局部内部类定义中的名:C
输出外部类定义的名字:B
输出包含内部类的方法中定义的名字A
我要访问包含内部类的方法中的属性值:A
我要访问外部类的属性值:A
- 匿名内部类
定义语法:
其实我感觉从说明或者下面的语法中不能体现匿名内部类,这个类字;但是生成的两个class文件确实证明是类
- 本质是继承了该类或者实现了该接口的匿名对象
- 匿名所以就没有名字,我们要表示他就得继承一个类或实现某个接口。和外部类产生关系以此生存;
new 实现接口()
{
//匿名内部类类体部分
}
new 父类构造器(实参列表)
{
//匿名内部类类体部分
}
- 匿名内部类没有类名,所以不能定义构造器(因为他没有类名,无法定义构造器)
- 在创建匿名内部类的时候会立即创建它的实例,所以匿名内部类不能是抽象类,必须实现接口或者父类中所有的抽象方法;
- 匿名内部类或继承一个父类(有且仅有一个)或者实现一个接口(有且仅有一个)实现父类中或者接口中的抽象方法,可以改变父类中的方法,添加自定义的方法(只能通过看是class或interface来确定是继承还是实现???)
- 匿名内部类必须实现接口或者抽象父类的所有抽象方法(有多少实现或者重写多少)
package 匿名内部类;
public class AnimalTest {
String name = "外部类名字";
public AnimalTest() {
}
public AnimalTest(String string){
// TODO Auto-generated constructor stub }
}
public void methodOuter() {
System.out.println("外部类方法");
}
class Inner{
private String name;
//String name = "内部类名字";
public Inner(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
void methodAbstractA() {//外部类中的静态方法,需要匿名内部类去实现的
System.out.println("不一定是抽象的" +" "+ pig.name);//開始沒有🐖,因为在構造方法中没有加上this.name = name;没有传值的过程
}
void methodAbstractB() {
}
}
//Inner pig = new Inner("猪") {//重写父类中的抽象方法,🐖继承Inner,但我这里不是匿名
@Override
new Inner("猪") {
void methodAbstractA() {
methodOuter();
// TODO Auto-generated method stub
System.out.println("抽象方法A");
super.methodAbstractA();
}
@Override
void methodAbstractB() {
// TODO Auto-generated method stub
System.out.println("抽象方法B");
super.methodAbstractB();
}
};
public void println() {
pig.methodAbstractA();
}
public static void main(String[] args) {
AnimalTest at = new AnimalTest();
at.println();
}
}
执行结果为:
外部类方法
抽象方法A
不一定是抽象的 猪
例子二:
定义接口:
interfance Product
{
public double getPrice();
public String getName();
}
类中去实现它
public class Anonymous
{
public void test (Product p)
{
System.out.println(p.getName()+"--------"+p.getPrice());
}
public static void main(String [ ] args )
{
Anonymous as= new Anonymous ();
as.test(new Product( )//此处实现接口并实现抽象方法
{
public double getPrice( )//实现方法
{
return 8888;
}
public String getName( )//实现方法
{
return "I can do it ";
}
});
}
}
/*定义了一个类Anonymous,在类里定义了一个test方法。然后就是创建Anonymous对象,调用他的实例方法test()。不过调用test()方法时,要传入一个Product对象。
但是由于Product是一个接口,无法创建象,所以要实现该接口。因此此处采用匿名内部类的方式进行,并实现接口中全部的抽象方法!*/
- 静态内部类
- 用static修饰的内部类,称为静态内部类,完全属于外部类本身,不属于外部类的某一个对象;(它可以完全独立存在)
- static关键字的作用时把修饰的成员变量变成类相关,而不是实例相关;(可以理解为一个新类,疑问:那为什么不新生成一个字节码文件)
- 静态内部类可以包含静态成员,也可以包含非静态成员,但是在非静态内部类中不可以声明静态成员;
按照之前的想法,静态修饰后属于类本身。在类加载时就同步加载了,但是非静态修饰属于对象,
静态变量与静态方法:数据存放的位置和普通变量不同;存放在class文件中指你的程序运行之前就存在数据了;
普通变量与方法:程序运行之后存放在堆栈中。 根据这个执行的先后顺序可以明白
- 静态内部类内部不可以访问外部类的实例,只能访问外部类的类成员(static修饰);
结合前面的:静态内部类和外部类无关,还想去调用外部类没有生成(因为数据对象,不是类。还没有加载)的数据
- 外部类不可以定义为静态类,java中静态类只有一种,就是静态内部类;
- 外部类如何调用静态内部类的属性和方法:
- 外部类可以创建静态内部类实例的方法调用静态内部类的非静态属性和方法;
- 外部类可以直接"外部类.内部类.属性(方法)"的方式直接调用静态内部类中的静态属性和方法
- 如何创建静态内部类实例
- 外部类中:外部类名.内部类名 name = new 外部类名.内部类名();
- 外部类中:内部类名 name = new 内部类名();
package 匿名内部类;
//这个demo涵盖了上面的所有点
public class StaticInner {
private String nameA = "非静态外部类名A";
private void methodOutA() {
System.out.println("非静态外部类方法A");
}
private static String nameB = "重名静态外部类名B";
private static void methodOutB() {
System.out.println("重名静态外部类方法B");
}
private String nameC = "非静态外部类名C";
private void methodOutC() {
System.out.println("非静态外部类方法C");
}
//你看里边的变量名nameB和methodB都是一致的但是没有冲突,是不是说明了静态内部类和外部类无关
private static class Inner{
private static String nameB = "重名静态内部类名B";
private static void methodOutB() {
System.out.println("重名静态内部类方法B");
}
private String nameD = "静态内部名D";
private void methodInD() {
System.out.println("静态内部方法名D");
}
private static String nameC = "静态内部类名C";
private static void methodOutC() {
System.out.println("静态内部类方法C");
}
}
//Inner in = new Inner();
public static void main(String[] args) {
Inner inA = new Inner();//如果时普通内部类,在这个静态主方法中创建普通对象,是会报错的 //创建静态内部类的第一种方式
System.out.println(inA.nameD + " " + inA.nameC );//这里访问的时
StaticInner.Inner inB = new StaticInner.Inner();//创建静态内部类的第二种方式
System.out.println(inB.nameD + " " + inB.nameC);
//Inner inC = new StaticInner().new Inner();//报错:Illegal enclosing instance specification for type StaticInner.Inner
//上面的报错是因为使用了之前非静态内部类的方法去创建对象,相当于绑定了外部类,这是和静态内部类不符的,所以有问题
//System.out.println(inC.nameA + inC.nameB);
inA.methodInD();
inB.methodInD();
//inC.methodInA();
//System.out.println(inA.nameA);这里静态内部类访问外部类非静态就报错了
System.out.println(StaticInner.Inner.nameB); //这个时直接通过外部类.内部类.属性(方法)去访问匿名内部类的东西
StaticInner si = new StaticInner();//这个时外部类的对象
System.out.println(si.nameB); //这里外部类的对象不能访问静态内部类的任何变量
}
}
执行结果为:
静态内部名D 静态内部类名C
静态内部名D 静态内部类名C
静态内部方法名D
静态内部方法名D
重名静态内部类名B
重名静态外部类名B
注意:
一、内部类是如何体现封装的
如前面所说
二、内部类的多继承
运动类中一个方法跳远
娱乐类中有一个方法说打游戏
package 匿名内部类;
//创建一个运动类
public class Excersise {
public void exec() {
System.out.println("通用运动方法");
}
}
package 匿名内部类;
//创建一个娱乐类
public class Entertainment {
public void Happy() {
System.out.println("娱乐的方式");
}
}
package 匿名内部类;
//着这个People类中,有内部类run和Game分别继承Excersise和Entertainment。重写了父类的方法
//然后在外部类之外创建内部类对象,用以访问两个内部类,从而达到“多继承的效果”;
public class People {
private class run extends Excersise{
@Override
public void exec() {
// TODO Auto-generated method stub
System.out.println("我运动的方法是跑");
}
}
private class Game extends Entertainment{
@Override
public void Happy() {
// TODO Auto-generated method stub
System.out.println("我娱乐的方式是打游戏");
}
}
public static void main(String[] args) {
People pp = new People();
pp.new run().exec();
pp.new Game().Happy();
}
}
执行结果:
我运动的方法是跑
我娱乐的方式是打游戏