比如现在有一个Student
类,里面啥也没有写:
/**
* ClassName: Student
* Package: PACKAGE_NAME
* Description:
*
* @Author 雨翼轻尘
* @Create 2024/1/31 0031 11:39
*/
public class Student {
}
然后还有一个测试类Test
:
/**
* ClassName: Test
* Package: PACKAGE_NAME
* Description:
*
* @Author 雨翼轻尘
* @Create 2024/1/31 0031 11:39
*/
public class Test {
public static void main(String[] args) {
//类->对象 格式:类名Student 对象名stu = new 类名Student();
Student stu=new Student();
}
}
️类->对象
格式:类名Student 对象名stu = new 类名Student();
如下:
public class Test {
public static void main(String[] args) {
//类->对象 格式:类名Student 对象名stu = new 类名Student();
Student stu=new Student();
}
}
现在打印出来就是地址值:
如果这样,也是地址值:
每new
一次,就会创建一个对象,相当于在堆中开辟了一块空间,所以地址值都不一样,如下:
public class Test {
public static void main(String[] args) {
//类->对象 格式:类名Student 对象名stu = new 类名Student();
Student stu=new Student();
System.out.println(stu); //test.Student@4eec7777
System.out.println(new Student()); //test.Student@3b07d329
System.out.println(new Student()); //test.Student@41629346
}
}
上面的stu
是有名字的对象,而现在的new Student()
没有对象名,叫做匿名对象。
有了new关键字,就表示在堆里面创建了一个新的空间。
现在在Student
类里面加上属性,比如:
public class Student {
String name; //姓名
}
正常情况下,name
可以赋值:
public class Test {
public static void main(String[] args) {
//类->对象 格式:类名Student 对象名stu = new 类名Student();
Student stu=new Student();
System.out.println(stu); //test.Student@4eec7777
stu.name="张三";
System.out.println(stu.name); //张三
}
}
打印出来就是“张三”:
那么new Student()
可以给name
赋值吗?
是可以的。
它是一个匿名对象,虽然没有名字,但是它可以给属性赋值的。如下:
public class Test {
public static void main(String[] args) {
System.out.println(new Student().name="李四"); //test.Student@3b07d329
System.out.println(new Student()); //test.Student@41629346
}
}
输出:
“匿名对象”只不过是一个没有名字的对象而已,依然是一个对象。
若是方法依然可以调用的,比如现在写一个方法eat
,如下:
public class Student {
String name; //姓名
public void eat(){
System.out.println("使劲吃...");
}
}
测试类里面:
public class Test {
public static void main(String[] args) {
//类->对象 格式:类名Student 对象名stu = new 类名Student();
Student stu=new Student();
System.out.println(stu); //test.Student@4eec7777
stu.name="张三";
System.out.println(stu.name); //张三
stu.eat();
System.out.println(new Student().name="李四"); //test.Student@3b07d329
System.out.println(new Student()); //test.Student@41629346
new Student().eat();
}
}
输出结果:
像这样直接new了一个类名,但是没有给对象名的,叫做“匿名对象”。
区别就是,有名的对象它可以多次使用,而匿名对象却只能使用一次。
提供一个接口IA
,里面写一个抽象方法play
,如下:
package test;
/**
* ClassName: IA
* Package: test
* Description:
*
* @Author 雨翼轻尘
* @Create 2024/1/31 0031 12:08
*/
public interface IA {
//抽象方法
void play();
}
抽象方法省略了public abstract
。
抽象方法要想重写,需要有子类去实现这个接口。
接下来写一个实现类IAImpl
,将接口里面的抽象方法重写一下,如下:
package test;
/**
* ClassName: IAImpl
* Package: test
* Description:
*
* @Author 雨翼轻尘
* @Create 2024/1/31 0031 12:12
*/
public class IAImpl implements IA{
@Override
public void play() {
System.out.println("打游戏...");
}
}
然后再来一个测试类IATest
,以多态的方式创建接口:
package test;
/**
* ClassName: IATest
* Package: test
* Description:
*
* @Author 雨翼轻尘
* @Create 2024/1/31 0031 12:14
*/
public class IATest {
public static void main(String[] args) {
IA ia=new IAImpl(); //多态
}
}
IA ia=new IAImpl();
,接口不能传对象,口诀:多态–“父父new子”。
实现类可以看成继承关系。
现在来使用ia调用play
方法:
public class IATest {
public static void main(String[] args) {
IA ia=new IAImpl(); //多态
ia.play(); //编译看左,运行看右
}
}
输出:
ia.play();
“编译看左,运行看右”,接口IA
里面有play
方法,它被实现类IAImpl
重写了,所以执行的时候是看实现类里面的。
现在我们来看一下这个蓝色部分,这个括号里面只有一个方法的重写:
之前说接口不能new,我们来看一下这样:
看一下刚才的两个蓝色部分,有什么区别?
没有区别!只不过右边多了一个最后的分号。
既然花括号里面的内容和实现类的一模一样,那我们可以使用i调用里面的方法play
,如下:
public class IATest {
public static void main(String[] args) {
IA ia=new IAImpl(); //多态
ia.play(); //编译看左,运行看右
System.out.println("------------------");
IA i=new IA() {
@Override
public void play() {
System.out.println("打游戏哈哈哈...");
}
};
i.play();
}
}
打印输出:
可以看到,调用的是花括号里面重写IA接口的方法。
我们new了一个接口之后,后面的大括号里面可以看作一个类的结构。如下:
在花括号里面是对方法的重写,重写的是IA接口的抽象方法。
现在写一个IB接口
:
public interface IB {
//抽象方法
void sleep();
}
再写一个测试类IBTest
:
public class IBTest {
public static void main(String[] args) {
}
}
目前IB接口没有实现类,还可以创建对象吗?
可以的,如下:
public class IBTest {
public static void main(String[] args) {
IB ib=new IB() {
@Override
public void sleep() {
}
};
}
}
这个结构和它的实现类结构是一样的(蓝色部分):
现在就不需要接口的实现类了,上面蓝色部分就是它的匿名实现类
。
通过ib.sleep()
来调用重写的抽象方法:
public class IBTest {
public static void main(String[] args) {
IB ib=new IB() {
@Override
public void sleep() {
System.out.println("睡觉...");
}
};
ib.sleep();
}
}
输出:
这就是匿名内部类,new的接口,相当于是把实现类的结构拿了过来,重写了一下。
还有一种写法。
刚才说了匿名对象,可以直接拿匿名对象去调用方法。
同样,我们还可以使用匿名内部类直接调用方法。
这个叫做创建“匿名实现类的有名对象”,如下结构:
IB ib = new IB(){
//sleep()方法的重写
};
ib.sleep(); //用ib调用方法sleep()
现在我们直接new一个接口IB
:
new IB(){
//sleep()方法的重写
}
然后直接用它调用sleep()
方法,如下:
new IB(){
//sleep()方法的重写
}.sleep();
代码
public class IBTest {
public static void main(String[] args) {
IB ib=new IB() {
@Override
public void sleep() {
System.out.println("睡觉...");
}
};
ib.sleep();
System.out.println("-------");
new IB(){
@Override
public void sleep() {
System.out.println("晚安喽");
}
}.sleep();
}
}
输出
这里的ib
就表示:
那就可以直接拿它调用sleep()
方法:
看一下正常的一般写法:
再看一下这两种方式: