面向对象进阶
一、抽象类
1.抽象方法
将 共性的 行为(方法)抽取到父类之后,由于每一个子类执行的类容是不一样的,所以,在父类中不能确定具体的方法体,该方法就可以定义为抽象方法****
2.抽象类:
如果一个类中存在抽象方法,那么该类就必须声明为抽象类
3.抽象方法和抽象类的定义格式
(1)抽象方法的定义格式
public abstract 返回值类型 方法名 (参数列表){};
(2)抽象类的定义格式
public abstract class 类名{};
4.抽象类和抽象方法的注意事项
🔺抽象类不能实例化(不能创建对象)
🔺抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
🔺抽象类可以有构造方法
🔺抽象类的子类要么是抽象类,要么重写抽象类中的所有抽象方法
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test01;
//有抽象方法的一定是抽象类
public abstract class Person {
private String name;
private int age;
//抽象类中可以有构造方法(空参、含参)
//这里的构造方法的作用:当创建子类对象时,给属性进行赋值的
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void work();
//抽象类中不一定有抽象方法,
public void sleep(){
System.out.println("睡觉"); //抽象类中没有抽象方法不会报错
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test01;
//抽象类的子类要么是抽象类
//要么是重写抽象类中的所有方法
public class Student extends Person {
//重写所有方法
public Student() {
}
public Student(String name, int age) {
super(name, age);
}
@Override
public void work() {
System.out.println("学生的工作i时学习");
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test01;
//抽象类的子类要么是重写所有方法,要么自己也是抽象类
//这里抽象类的子类Teacher自己是 抽象类
//但是抽象类不能创建自己的对象
//如果要创建自己的类,就需要新建这个类的子类重写这个类的所有方法
public abstract class Teacher extends Person{
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test01;
public class Test {
public static void main(String[] args) {
//1.抽象类不能(实例化)创建对象
// Person p = new Person(); //Person是抽象的; 无法实例化
Student s = new Student("zhangsan",22);
System.out.println(s.getName()+","+s.getAge());
}
}
abstract练习
需求:
青蛙frog 属性:名字,年龄 行为:吃虫子,喝水
狗dog 属性:名字,年龄 行为:吃骨头,喝水
山羊sheep 属性:名字,年龄 行为:吃草,喝水
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test02;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
public void drink(){
System.out.println("喝水");
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test02;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗在啃骨头");
}
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test02;
public class Frog extends Animal {
@Override
public void eat() {
System.out.println("青蛙在吃虫子");
}
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test02;
public class Sheep extends Animal {
@Override
public void eat() {
System.out.println("山羊在吃草");
}
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
}
package com_03_mianxaingduixiang.Demo_06_Abstract.abstract_test02;
/*
需求:
青蛙frog 属性:名字,年龄 行为:吃虫子,喝水
狗dog 属性:名字,年龄 行为:吃骨头,喝水
山羊sheep 属性:名字,年龄 行为:吃草,喝水
*/
public class Test {
public static void main(String[] args) {
Dog d = new Dog("大黄",12);
Frog f = new Frog("小绿",4);
Sheep s = new Sheep("肖恩",9);
System.out.println(d.getName()+","+d.getAge());
d.eat();d.drink();
System.out.println(f.getName()+","+f.getAge());
f.eat();f.drink();
System.out.println(s.getName()+","+s.getAge());
s.eat();s.drink();
}
}
5.抽象类和抽象方法的意义
(1)疑问
把子类中共性的内容抽取到父类之后,由于方法体不确定,需要定义为抽象。子类使用时需要重写,但如果不抽取到父类中,直接写在子类里面不是更节约代码
★强制子类必须按照同一种格式进行重写(让代码格式统一)
二、接口
为什么会有接口?
接口:就是一种规则,是对行为的抽象
(1).接口的定义和使用
①接口关键字interface来定义
Public interface 接口名 { };
②接口不能实例化(不能创建对象)
③接口和类之间是实现关系,通过implements关键字表示
public class 类名 implements 接口名 { }
④接口的子类称为实现类
在实现类中,要么重写接口中的所有抽象方法(使用更多),要么自身是抽象类
⑤注意:
(1)接口和类的实现关系,可以单实现,也可以多实现
public class 类名 implements 接口名1,接口名2 { };
(2)实现类还可以在继承一个类的同时实现多个接口
public class 类名 extends 父类 implements 接口名1,接口名2 { } ;
⑥接口练习
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
public interface swim {
public abstract void swimming();
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
import jdk.swing.interop.SwingInterOpUtils;
public class Dog extends Animal implements swim{
public void swimming(){
System.out.println("狗会狗刨");
}
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗在吃骨头");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
public class Frog extends Animal implements swim {
public void swimming(){
System.out.println("青蛙会蛙泳");
}
@Override
public void eat() {
System.out.println("青蛙吃虫子");
}
public Frog() {
}
public Frog(String name, int age) {
super(name, age);
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
public class Rabbit extends Animal{
@Override
public void eat() {
System.out.println("兔子吃胡萝卜");
}
public Rabbit() {
}
public Rabbit(String name, int age) {
super(name, age);
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test01;
public class Test {
public static void main(String[] args) {
Rabbit r = new Rabbit("xiaobai",2);
r.eat();
Dog d = new Dog("dahuanug",3);
d.eat();d.swimming();
Frog f = new Frog("xiaolv",2);
f.eat();f.swimming();
}
}
(2)接口里面成员的特点
①成员变量
接口中的成员变量只能是常量
默认修饰符 : public static final
②构造方法
接口中不能有构造方法
③成员方法
默认修饰符:public abstract
★jdk7以前:接口中只能定义抽象方法
★jdk8的新特性:接口中可以定义有方法体的方法
★jkd9的新特性:接口中可以定义私有方法
(3)接口和类之间的关系
①类和类之间的关系
继承关系,只能单继承,不能多继承,但是可以多层继承
②类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
③接口和接口的关系
继承关系,可以单继承,也可以多继承
细节:如果实现类实现了最下面的子接口的话,那么就需要重写所有的抽象方法
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test04;
//接口1
public interface inter1 {
public abstract void method1();
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test04;
//接口2
public interface inter2 {
public abstract void method2();
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test04;
//接口3,继承了接口1和接口2
public interface inter3 extends inter1,inter2 {
public abstract void method3();
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test04;
//实现类
public class Interimpl implements inter3{
@Override
public void method3() {
}
@Override
public void method1() {
}
@Override
public void method2() {
}
}
(4)JDK8 开始接口中新增的方法
1.JDK 7以前
接口中只能定义抽象方法
2.JDK 8的新特性
接口中可以定义有方法体的方法(默认、静态)
(1)默认方法
★允许在接口中定义默认方法,需要使用关键字default修饰
🔺作用:解决接口升级的问题
★接口中默认方法的定义格式:
🔺public default 返回值类型 方法名 (参数列表){…};
🔺示例:public default void show(){…};
★接口中默认方法的注意事项;
🔺默认方法不是抽象方法,所以不强制被重写,但如果被重写,重写的时候去掉default关键字
🔺public 可以省略,但是default不可以省略
🔺如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test07;
public interface interB {
//默认方法
//如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
//两个接口中含有相同名字的方法,那么实现类里面就必须重写这个方法
public default void show2(){
System.out.println("interB接口中的默认方法------show2");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test07;
public interface interB {
//默认方法
//如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
//两个接口中含有相同名字的方法,那么实现类里面就必须重写这个方法
public default void show2(){
System.out.println("interB接口中的默认方法------show2");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test07;
public class interImpl implements interA,interB {
@Override
public void show1() {
System.out.println("重写之后的抽象方法show1");
}
//这里默认方法不重写也不会报错
//但如果要重写就必须要去掉default关键字
@Override
public void show2() {
System.out.println("重写之后的默认方法show2");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test07;
/*
★接口中默认方法的定义格式:
🔺public default 返回值类型 方法名 (参数列表){...};
🔺示例:public default void show(){...};
★接口中默认方法的注意事项;
🔺默认方法不是抽象方法,所以不强制被重写,但是如果被重写,重写的时候去掉default关键字
🔺public 可以省略,但是default不可以省略
🔺如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
*/
public class Test {
public static void main(String[] args) {
//创建实现类对象
interImpl i1 = new interImpl();
i1.show1();
i1.show2();
}
}
(2)静态方法
★允许在接口中定义静态方法,需要用static修饰
★接口中静态方法的定义格式:
🔺格式:public static 返回值类型 方法名(){…};
🔺示例:public static void show ( ) {…};
★接口中静态方法的注意事项:
🔺静态方法只能通过接口名调用,不能通过实现类或者对象名调用
🔺public 可以省略,但是static不可以省略
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test08;
public interface interA {
//接口中的抽象方法
public abstract void method();
//接口中的静态方法不能被重写
public static void show(){
System.out.println("interA接口中的静态方法-------show");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test08;
public class interImpl implements interA{
@Override
public void method() {
System.out.println("重写之后的method抽象方法");
}
public static void show(){
System.out.println("实现类里面的静态方法----show");
}
}
package com_03_mianxaingduixiang.Demo_07_inteface.interface_test08;
import com_03_mianxaingduixiang.Demo_07_inteface.interface_test02.inter;
/*
★允许在接口中定义静态方法,需要用static修饰
★接口中静态方法的定义格式:
🔺格式:public static 返回值类型 方法名(){...};
🔺示例:public static void show ( ) {...};
★接口中静态方法的注意事项:
🔺静态方法只能通过接口名调用,不能通过实现类或者对象名调用
🔺public 可以省略,但是static不可以省略
*/
public class Test {
public static void main(String[] args) {
//调用接口中的静态方法
interA.show();
//调用实现类中的静态方法
interImpl.show();
//子类把从父类继承下来的虚方法表里面的方法进行覆盖了,这才叫重写
}
}
3.JDK 9的新特性
接口中可以定义私有方法
定义私有方法,用来服务接口中的重复代码
(1)定义格式
①格式1:private vod show(){}
private void 方法名 (参数列表){ }
②private static void show () {}
private static 返回值类型 方法名(参数列表){}
4.总结:
(1)jdk7以前:接口中只能定义抽象方法
(2)jdk8:接口中可以定义有方法体的方法(默认、静态)
(3)jdk9:接口中可以定义私有方法
(4)私有方法分两种:
1.普通的私有方法(给默认方法服务的)2.静态的私有方法(给静态方法服务的)
(5)接口的应用
1.接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了
2.当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态
例如:public static void (interface A){}
(6)适配器设计模式
1.设计模式(Design Patern):
是一套被反复利用、多打湖人只晓得、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性
简单理解:设计模式就是各种套路
2.适配器设计模式:
解决接口与接口实现类之间的矛盾问题
总结:
1.当一个接口中抽象方法过多,但是我们只要使用其中一部分的时候,就可以用适配器设计模式
2.书写步骤:
编写中间类 XXXAdapter,实现对应的接口
对接口中的抽象方法进行空实现(重写所有方法,但不写方法体)
让真正的实现类继承中间类,并重写需要用到的方法
为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰
三、内部类
1.什么是内部类:
在一个类的里面再定义一个类
public class Outer{ //外部类
public class Inner{ //内部类
}
}
public class Test{ //外部其他类
public sattic void main(String []args){
}
}
什么时候会用到内部类呢:
B类表示的事务是A类的一部分,且B单独存在没有意义
类的五大成员:属性、方法、构造方法、代码块、内部类
2.为什么要学习内部类:
需求:写一个JavaBean类描述汽车
属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限
public class Car{ //外部类
String carname;
int carAge;
String carColor;
//内部类表示的事务是外部类的一部分
//且内部类单独出现没有任何意义
class Engine{ //内部类
String engineName;
int EngineName;
}
}
3.内部类的访问特点:
(1)内部类可以直接访问外部内的成员
(2)外部类要访问内部类的成员,必须要创建对象
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test01;
public class Car {
String carName;
int carAge;
private String carColor;
public void show2(){
//外部类可以访问外部类的所有成员
System.out.println(carAge+","+carName+","+carColor);
//但不能直接访问内部类的成员,会报错
//System.out.println(EngineName+","+EngineAge);
//如果非要访问内部类的成员,就必须要创建对象
Engine e = new Engine();
System.out.println(e.EngineName+","+e.EngineAge);
}
class Engine {
private String EngineName;
int EngineAge;
public void show(){
//内部类可以直接访问外部类的成员,包括私有
System.out.println(carAge+","+carName+","+carColor);
//内部类也可以直接访问内部类里面的所有成员,包括私有
System.out.println(EngineName+","+EngineAge);
}
}
}
4.成员内部类
(1)成员内部类的代码如何书写
★ 成员内部类是写在成员位置的,属于外部类的成员(类中方法外)
★成员内部类可以被一些修饰符所修饰,比如:private(本类里面)、默认(本包下的所有子类)、protected(本包或其他包的子类里面)、public(所有位置)、static等
★在成员内部类的里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量
public class Car{ //外部类
String carname;
int carAge;
String carColor;
class Engine{ //成员内部类
String engineName;
int EngineName;
}
}
(2)如何创建成员内部类的对象
①在外部内中编写方法,对外提供内部类的对象
使用场景:当内部类被private修饰时,在外部类编写方法,对外提供内部类对象
②可以在外部类直接创建:当成员内部类被非私有修饰时直接创建
外部类名.内部类名. 对象名 = 外部类对象.内部类对象;
package com_03_mianxaingduixiang.InnerClass_test02;
public class Outer {
private class Inner{
//在内部类里面声明静态变量
//但是在JDK16之前不能在内部类里面声明静态变量
//static int a = 10;
}
//当内部类是私有的时候,可以在外部类里面内部类外面创建创建方法,对外提供内部类对象
public Inner getInstance(){
return new Inner();
}
}
package com_03_mianxaingduixiang.InnerClass_test02;
public class Test {
public static void main(String[] args) {
//创建对象的方式
//类名.对象名 = new 类名();
//Student s = new Stutdent();
//我要创建的是谁的对象===》内部类的对象
//如何创建成员内部类的对象
//①在外部内中编写方法,对外提供内部类的对象
//②可以在外部内直接创建内部类对象:
// 外部类名.内部类名. 对象名 = 外部类对象 .成员内部类对象;
// Outer .Inner oi = new Outer().new Inner(); 内部类私有的时候不能直接创建对象
Outer o = new Outer();
//调用方法,获取内部类的对象
System.out.println(o.getInstance());
}
}
(3)成员内部类如何获取外部类的成员变量
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test03;
public class Outer {
private int a = 10;
class Inner{
private int a = 20;
public void show(){
int a = 30;
Outer o1 = new Outer();
System.out.println(this.a); //20
System.out.println(a); //30
System.out.println(o1.a); //10
//Outer.this:表示获取了外部类对象的地址值
System.out.println(Outer.this.a); //10
}
}
}
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test03;
public class Test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
(4)总结:
①内部类的分类
成员内部类、静态内部类、局部内部类、匿名内部类
②什么是成员内部类
写在成员位置的,属于外部类的成员
③获取成员内部类对象的两种方式
方式一:当成员内部类被private修饰时,在外部类中编写方法,对外提供内部类对象
方式二:当成员内部类被非私有修饰时,直接创建对象
外部类 . 内部类 对象名 = new 外部类(). new内部类();
Outer . Inner oi = new Outer . new Inner();
④外部类成员和内部类成员变量重名时,在内部类如何访问
System.out.println( Outer . this . 变量名);
5.静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果像访问非静态的需要创建外部类的对象
public class Outer{ //外部类
String name;
int Age;
int color
static class Inner{ //静态内部类
String name;
int Age;
}
}
1.静态内部类
(1)创建静态内部类的对象
外部类名 . 内部类名 对象名 = new 外部类名 . 内部类名();(要和非静态的创建对象区分)
(2)调用非静态方法的格式
先创建对象,用对象调用
(3)调用静态方法的格式
外部类名 . 内部类名 . 方法名();
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test04;
public class Outer {
int a = 10;
static int b = 20;
//静态内部类
static class Inner{
public void show1(){
Outer o = new Outer();
System.out.println(o.a);
System.out.println(b);
System.out.println("非静态的方法被调用了");
}
public static void show2(){
Outer o = new Outer();
System.out.println(o.a);
System.out.println(b);
System.out.println("静态的方法被调用了");
}
}
}
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test04;
import javax.annotation.processing.SupportedAnnotationTypes;
public class Test {
public static void main(String[] args) {
Outer.Inner oi = new Outer.Inner();
oi.show1();
//虽然也可以直接调用静态方法,但是不提倡
//oi.show2();
Outer.Inner.show2();
}
}
(4)总结
(1)什么是静态内部类
静态内部类是一种特殊的成员内部类
(2)直接创建静态内部对象的方式
Outer .Inner oi = new Outer.Inner();
外部类名 . 内部类名 对象名 = new 外部类名 . 内部类名();
(3)如何调用静态内部类中的方法?
静态内部类只能访问外部类中的静态变量和静态方法
如果想访问非静态的需要创建外部类的对象
非静态方法:先创建对象,用对象调用
静态方法:外部类名 . 内部类名 . 方法名();
6.局部内部类
(1)什么是局部内部类
将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
(2)局部内部类的特点
外界无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test05;
/*
将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
外界无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
*/
public class Outer {
int b = 20;
public void show1(){
int a = 10;
//局部内部类
class Inner{
String name;
int age;
public void show2(){
//局部内部类可以直接访问外部类的成员和局部变量
System.out.println(b); //成员变量
System.out.println(a); //局部变量
System.out.println("局部内部类中的show2方法");
}
//jdk16之后可以定义静态
//public static void show3(){
public static void show3(){
System.out.println("局部内部类中的show2方法");
}
}
//在方法里面创建局部内部类的对象
Inner i = new Inner();
System.out.println(i.name+","+i.age);
//创建对象调用局部内部类里面的方法
i.show2();
i.show3();
//使用类名调用静态方法
Inner.show3();
}
}
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test05;
public class Test {
public static void main(String[] args) {
//外界无法直接使用局部内部类,需要在方法内部创建对象并使用
//无法直接使用show方法里面的局部变量a
Outer o = new Outer();
o.show1();
}
}
7.匿名内部类
(1)什么是匿名内部类
🔺匿名内部类本是上就越是隐藏了名字的内部类,这个内部类可以写在成员位置,也可以写在局部位置,只不过名字被隐藏了
(2)格式
new 类名或者接口名(){ //类名表示继承关系,接口表示实现关系
重写方法
};
🔺格式的细节:这个格式里面包含了三部分:继承/实现 、方法重写 、创建对象
例如:
new Inter(){
public void show(){
}
}
(3)使用场景
①当方法的参数是接口或者类时
②以接口为例,可以传递这个接口的实现类对象
③如果实现类只要使用一次,就可以用匿名内部类简化代码
代码演示:
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test06;
public class Test {
public static void main(String[] args) {
//编写匿名内部类的代码
new Swim(){
@Override
public void swim(){
System.out.println("重写之后的swim方法");
}
};
}
}
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test06;
public interface Swim {
public abstract void swim();
}
扩展:
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test06;
public class Test {
public static void main(String[] args) {
//编写匿名内部类的代码
new Swim(){
@Override
public void swim(){
System.out.println("重写之后的swim方法");
}
};
method(
new Animal(){
@Override
public void eat(){
System.out.println("狗吃骨头");
}
}
);
// new Animal(){
// @Override
// public void eat(){
// System.out.println("重写之后的eat方法");
// }
// };
}
public static void method(Animal a){
}
}
package com_03_mianxaingduixiang.Demo_08_InnerClass.InnerClass_test06;
public class Test2 {
public static void main(String[] args) {
//匿名内部类的格式
// new 类名(继承关系)/接口(实现关系)(){
// 重写方法
// }
//这个整体可以理解为Swim接口实现类的对象
Swim s = new Swim(){
@Override
public void swim() {
System.out.println("重写之后的swim方法");
}
};
//编译看左边,运行看右边,对象调用方法
s.swim();
//匿名实现类整体是是一个对象,所以可以调用方法
new Swim(){
@Override
public void swim() {
System.out.println("重写游泳方法");
}
//用整体来调用方法
}.swim();
}
}
四、拼图小游戏
1.目的
(1)将面向对象的知识点贯穿起来(循环、字符串、判断、集合)
(2)锻炼逻辑思维能力
(3)知到所学知识点在实际开发中的应用场景
涉及到的知识点;
封装、继承、多态、抽象类、接口、内部类、集合、字符串、数组、循环、判断
2.游戏主界面添加组件
(1)JFrame:(主窗体)
(2)JMenuBar:菜单
(3)JMenu:菜单选项
(4)JLabel:容器管理(文字、图片等)
3.事件
(1)定义:
就是可以被组件识别的操作,也就是当我们对组件干了某件事之后,就会执行相应的代码
(2)事件的核心要素
①事件源:按钮、图片、窗体
②事件:指某些操作鼠标点击、鼠标划入
③绑定监听:当事件源上发生了某个事件,则会执行某些代码
(3)常见的事件监听
①KeyListener:键盘监听
Modifier and Type | 方法 | 描述 |
---|---|---|
void | keyPressed ( KeyEvent e ) | 按下键时调用 |
void | keyReleased ( KeyEvent e ) | 当键已被释放时调用 |
void | keyTyped ( KeyEvent e ) | 键入键时调用 |
**细节1:**如果我们按下一个按键没有松开,那么会重复的去调用keyPressed方法
**细节2:**键盘里面众多案件,如何进行区分?
每一个按键都有一个编号与之对应,调用方法e.getKeyCode()可以获取到每一个按下的按键的编号
package com.kinbow.test;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class MyJFrame3 extends JFrame implements KeyListener {
public MyJFrame3 (){
//设置界面的宽高
this.setSize(603,688);
//设置界面的标题
this.setTitle("我的界面");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消默认的居中放置,只有取消了才会按照XY轴的形式添加组件
this.setLayout(null);
//给整个窗体添加键盘监听
//调用者this:表示本类对象,就是当前的界面对象,表示我要给整个页面添加监听
//addKeylistener :表示要给本界面添加键盘监听
//参数this : 表示当事件被出发之后,会执行本类中的对应代码
this.addKeyListener(this);
//显示界面
this.setVisible(true);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println("按下不松");
}
@Override
public void keyReleased(KeyEvent e) {
System.out.println("释放");
//e.getKeyCode() : 获取键盘上每一个按键的编号 与ASCII码表没有关系
int code = e.getKeyCode();
System.out.println("按下的按键是"+code);
if (code == 65){
System.out.println("现在按的是A");
}else if (code == 66){
System.out.println("现在按的是B");
}
}
}
②MouseListener:鼠标监听机制
划入动作
按下动作
松开动作
划出动作
如果想监听一个按钮的单击事件,有以下三种方式
★动作监听★鼠标监听中的单击事件★鼠标监听中的松开事件★
package com.kinbow.test;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
public class MyJFrame2 extends JFrame implements MouseListener {
//创建一个按钮对象
JButton jbt1 = new JButton("点我改变大小");
//创建一个按钮对象
JButton jbt2 = new JButton("点我改变位置");
public MyJFrame2 (){
//设置界面的宽高
this.setSize(603,688);
//设置界面的标题
this.setTitle("我的界面");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消默认的居中放置,只有取消了才会按照XY轴的形式添加组件
this.setLayout(null);
//给按钮设置宽高
jbt1.setBounds(0,0,100,50);
//给按钮绑定鼠标事件
jbt1.addMouseListener(this);
//给按钮设置宽高
jbt2.setBounds(100,0,100,50);
//给按钮添加事件
jbt2.addMouseListener(this);
//显示界面
this.setVisible(true);
//将按钮添加到窗体中
this.getContentPane().add(jbt1);
this.getContentPane().add(jbt2);
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("这是个单击事件");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("这是个按下不松事件");
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("这是个松开事件");
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("这是个划入事件");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("这是个划出事件");
}
}
方法摘要
Modifier and type | 方法 | 描述 |
void | mouseClicked(MouseEvent e) | 在组件上单击(按下并释放)鼠标按钮时调用 |
void | mouseEntered(MouseEvent e) | 当鼠标进入组件时调用 |
void | mouseExited(MouseEvent e) | 当鼠标退出组件时调用 |
void | mousePressed(MouseEvent e) | 在组件上按下鼠标按钮时调用 |
void | mouseReleased(MouseEvent e) | 在组件上释放鼠标按钮时调用 |
③ActionListener:行为(动作)监听
package com.kinbow.test;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class MyJFrame extends JFrame implements ActionListener{
//创建一个按钮对象
JButton jbt1 = new JButton("点我改变大小");
//创建一个按钮对象
JButton jbt2 = new JButton("点我改变位置");
public MyJFrame() {
//设置界面的宽高
this.setSize(603,688);
//设置界面的标题
this.setTitle("我的界面");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消默认的居中放置,只有取消了才会按照XY轴的形式添加组件
this.setLayout(null);
//给按钮设置宽高
jbt1.setBounds(0,0,100,50);
//给按钮添加事件
jbt1.addActionListener(this);
//给按钮设置宽高
jbt2.setBounds(100,0,100,50);
//给按钮添加事件
jbt2.addActionListener(this);
//显示界面
this.setVisible(true);
//将按钮添加到窗体中
this.getContentPane().add(jbt1);
this.getContentPane().add(jbt2);
}
@Override
public void actionPerformed(ActionEvent e) {
//对当前按钮进行判断
//获取当前被操作的按钮的对象
Object source = e.getSource();
if (source == jbt1){
jbt1.setSize(200,200);
}else if (source == jbt2){
Random r = new Random();
jbt2.setLocation(r.nextInt(500),r.nextInt(500));
}
}
}