面向对象编程
概念:
- 万物皆对象
- 面向对象值以属性和行为的观点去分析现实生活中的事物。
- 面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言进行表达的过程。
类与对象的概念:
-
对象主要指现实生活中客观存在的实体,在Java语言对象中体现为内存空间中的一块区域。
-
类简单来说就是分类,是对具有相同特性和行为的对个对象的抽象描述,在Java语言体中体现为一种引用类型数据,里面包含了描述特征/属性的成员变量以及描述行为的成员方法。
-
类是构建对象的模板,对象的数据结构由定义它的类来决定。
对象的创建
-
new 类名();
-
注意:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0yA3GrOQ-1589009946516)(C:\Users\86156\AppData\Roaming\Typora\typora-user-images\image-20200430105449072.png)]
//创建一个Person对象
Person p = new Person(); //数据类型(类名) 引用变量名 = new 类名();
引用的定义
//打印对象中的成员变量值
//引用变量名.成员变量名
System.out.println("我是" +p.name+ "今年" + p.age + "岁了");
//修改成员变量中的值
String name = "张三";
int age = 20;
//再次打印成员变量中的值
System.out.println("我是" +p.name+ "今年" + p.age + "岁了");
成员变量的初始值
成员方法的定义
返回值类型详解
-
返回值主要指从方法体内返回到方法体外的数据内容。
-
返回值类型主要指返回值的数据类型,可以是基本数据类型,也可以是引用数据类型。
-
当返回的数据内容是66时,则返回值类型写int即可。
-
在方法体中使用return关键字可以返回具体的数据内容并结束当前方法。
-
当返回的数据内容是66时,则方法体中写return 66;即可
形参类型的讲解
- 形参类型主要用于将方法体外的数据内容带入到方法体内部。
- 形式参数列表主要指多个形式参数组成的列表,语法格式如下:数据类型 形参变量名1,数据类型 形参变量名2,…
- 当带入的数据是"hello"时,则形参列表写String s即可
- 当带入的数据内容是66和"hello"时,则形参列表写int i,String s即可。
- 若该方法不需要带入任何数据内容时,则形参列表位置啥也不写即可。
方法的调用
-
引用变量名.成员方法名(实参列表);
-
实际参数列表主要用于对形式参数进行初始化操作,因此参数的个数、类型以及顺序都要完全一致。
-
实际参数可以传递直接量、变量、表达式、方法的调用等。
可变长参数
-
返回值类型 方法名(参数的类型… 参数名)
-
方法参数部分指定类型的参数个数是可以改变的,也就是0~n个。
-
一个方法的形参列表最多只能声明一个可变长形参,并且需要放到参数列表的末尾。
public class Test1 { public static void main(String[] args) { int a = 5; int b = 6; int res = Test1.max(a,b); //调用max方法,返回比较的结果 System.out.println(res); } public static int max(int ia,int ib){ return ia>ib?ia:ib; //使用三目运算符比较最大数 } }
错题集
正规的开发中都需要都需要正确的使用命名规范,下面的规范正确的是(B C D)
A、类名由多个单词组成时要求第一个单词的首字母小写。
B、特征名由多个单词组成时要求第一格单词的首字母小写。
C、成员方法名由多个单词组成时要求第一个单词的首字母小写。
D、引用变量名由多个单词组成时要求第一个单词的首字母小写。
方法和封装
构造方法的基本概念
class 类名 {
类名(形参变量){
构造方法体;
}
}
举例:
class Person {
Person() { //Person类中的构造方法
}
}
构造方法名与类名完全相同并且没有返回值类型,连void都不许有。
默认构造方法
-
当一个类中没有定义任何构造方法时,编译器会自动添加一个无参构造方法,叫做默认/缺省构造方法,如:Person(){}
-
若类中出现了构造方法,则编译器不再提供任何形式的构造方法。
构造方法的作用
- 使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作。
方法重载的概念
- 若方法名称相同,参数列表不同,这样的方法之间构成重载关系(Overload)。
//自定义无参构造方法
public Point() {}
public Point(int i,int j) {
x = i; //将i的值赋值给x
y = j; //将y的值赋值给j
}
- 方法重载的条件:方法名相同,参数的个数、顺序、类型不同则构成方法重载。方法重载与返回值类型无关,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
- 判断方法能否构成重载的核心:调用方法时能否能否加以区分。
方法重载的实际意义
- 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现不同的功能。
- 如:java.io.PrintStream类中的println方法。
this关键字
this的基本概念:
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
工作原理
- 在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀,
而this.相当于汉语中"我的",当不同的对象调用同一个方法时,由于调用
方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之
不同。
//自定义成员方法实现所有特征的打印 隐含关键字,this关键字表示当前正在调用的对象
Person this = p1; this.name = p1.name = 张飞
Person this = p2; this.name = p2.name = 关羽
public void show() {
System.out.println("我是" + name + "今年" + age + "岁");
}
使用方式
- 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就
近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前
缀,明确要求该变量是成员变量(重中之重在工作中都是这样的)。
public Person(String name,int age) {
this.name = name; //this表示当前正在构造的对象,对象中的name和age是成员变量name和age
this.age = age;
}
public void grow(int age) {
this.age += age;
}
//之所以加this关键字,是因为不加this关键字会产生歧义,为了明确声明它是成员变量而此方法没有歧义,所以不需要加
public void grow() {
age++;
}
public void show() {
//每当打印成员变量的数值时,让年龄增长一岁
grow();
System.out.println("我是" + name + "今年" + age + "岁");
}
- this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以
作为方法的返回值(重点)。
//自定义成员方法实现Person类型对象的获取并返回的行为
Person getPerson() {
//返回当前调用对象本身 Person p = new Person(); return p;
return this;
}
//调用成员方法获取对象
Person p1 = new Person("张三",23);
Person p2 = p1.getPerson();
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
-
在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法(了解)。
Boy(String name){ //调用本类中的无参构造方法 this(); System.out.println("有参构造方法"); this.name = name; }
引用变量的注意事项
- 引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不
指向任何对象。 - 当某个引用类型变量为null时无法对对象实施访问(因为它没有指向任何
对象)。此时,如果通过引用访问成员变量或调用方法,会产生
NullPointerException 异常。
Boy b3 = null;
b3.show(); //编译OK,运行会发生NullPointerException空指针异常 算术异常、数组下标越界异常
递归的基本概念
- 递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式。
注意事项
-
使用递归必须有递归的规律以及退出条件。
-
使用递归必须使得问题简单化而不是复杂化。
-
若递归影响到程序的执行性能,则使用递推取代之。
面向对象三大特性-封装
封装
封装的概念:
- 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无
论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活
不符。 - 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐
藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
封装的实现流程
- 私有化成员变量,使用private关键字修饰。
- 提供公有的get和set方法,并在方法体中进行合理值的判断。
- 在构造方法中调用set方法进行合理值的判断。
JavaBean的概念
- JavaBean是一种Java语言写成的可重用组件,其它Java 类可以通过反射机
制发现和操作这些JavaBean 的属性。 - JavaBean本质上就是符合以下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
总结
-
构造方法(重中之重)
语法格式、默认构造方法、实现成员变量的初始化
-
方法重载(重点)
概念、体现形式、实际意义
-
this关键字(原理)
概念、原理、使用方式
-
递归(难点)
概念、使用原则
-
封装(重中之重)
概念、实现流程
static关键字和继承
static关键字基本概念
-
使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层
级提升为类层级,也就是整个类只有一份并被所有对象共享,该成员变
量随着类的加载准备就绪,与是否创建对象无关。 -
static关键字修饰的成员可以使用引用.的方式访问,但推荐类名.的方式。
使用方式
-
在非静态成员方法中既能访问非静态的成员又能访问静态的成员。
(成员:成员变量 + 成员方法, 静态成员被所有对象共享) -
在静态成员方法中只能访问静态成员不能访问非静态成员。
(成员:成员变量 + 成员方法, 因为此时可能还没有创建对象) -
在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用
static关键字修饰。(不能滥用static关键字)
构造和静态代码块(熟悉)
- 构造块:在类体中直接用{} 括起来的代码块。
- 每创建一个对象都会执行一次构造块。
- 静态代码块:使用static关键字修饰的构造块。
- 静态代码块随着类加载时执行一次。
//构造代码块:当需要在执行构造方法体之前做一些准备工作时,则将准备工作相关的代码写在构造块中即可,比如:对 成员变量进行的统一初始化操作
//每创建一次对象,就会执行一次构造代码块
{
System.out.println("构造代码块"); //(2)
}
//静态代码块随着类加载而准备就绪,与创建对象无关会先于构造块执行,只会执行一次
//当需要在执行构造代码块之前随着类的加载做一些准备工作时,则编写代码到静态代码块中
static {
System.out.println("静态代码块"); //执行顺序 (1)
}
//自定义构造方法
public BlockTest() { //(3)
System.out.println("构造方法体");
}
单例设计模式的概念
- 在某些特殊场合中,一个类对外提供且只提供一个对象时,这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式。
案例题目(重中之重)
-
编程实现Singleton类的封装。
-
编程实现SingletonTest类对Singleton类进行测试,要求main方法中能得到且只能得到该类的一个对象。
public class Singleton {
//1、私有化构造方法,使用private关键字修饰
private Singleton() {}
//2、声明本类类型的引用指向本类类型的对象,使用private static关键字共同修饰
//private static Singleton sin = new Singleton(); //饿汉式,一上来就创建对象
private static Singleton sin = null; //懒汉式,先让对象为空,当调用方法时才创建对象
//3、提供共有的get方法负责将对象返回出去 使用public static关键字共同修饰
public static Singleton getInstance() {
//return sin;
if(null == sin) { //如果对象为空,则创建对象
sin = new Singletion(); //第一次调用getInstance()方法时,条件成立创建对象并返回
}
return sin; //第二次调用getInstance()方法条件不成立,直接返回
}
}
//测试
public static void main(String[] args) {
Singleton sin1 = Singleton.getInstance();
Singleton sin2 = Singleton.getInstance();
//比较sin1和sin2的地址值是否相等,因为调用getInstance()方法,方法体只new了一次对象,所以结果为true
System.out.println(sin1 == sin2);
}
单例设计模式的执行流程
单例设计模式实现流程
- 私有化构造方法,使用private关键字修饰。
- 声明本类类型的引用指向本类类型的对象,并使用private static 关键字共同修饰。
- 提供公有的get方法负责将对象返回出去,并使用public static 关键字共同修饰。
单例设计模式实现方式:
- 单例设计模式的实现方式有两种:饿汉式 和 懒汉式,在以后的开发中推
荐饿汉式。
面向对象编程三大特性-继承
继承的概念
-
当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成
一个公共类,让多个类吸收公共类中已有特征和行为而在多个类型只需
要编写自己独有特征和行为的机制,叫做继承。 -
在Java语言中使用extends(扩展)关键字来表示继承关系。
-
如:
public class Worker extends Person{} - 表示Worker类继承自Person类
其中Person类叫做超类、父类、基类。
其中Worker类叫做派生类、子类、孩子类。 -
使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。
继承的特点
-
子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
-
无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,
来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代
码super()的效果。
- 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
- Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父
类,但一个父类可以有多个子类。
方法重写的概念
- 从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写
一个和父类一样的方法来覆盖从父类中继承下来的版本,该方式就叫做
方法的重写(Override)。
方法重写的原则
- 要求方法名相同、参数列表相同以及返回值类型相同,从Java5开始允许返回子类类型。
- 要求方法的访问权限不能变小,可以相同或者变大。
- 要求方法不能抛出更大的异常。
访问控制
常用的访问控制符:
注意事项:
- public修饰的成员可以在任意位置使用。
- private修饰的成员只能在本类内部使用。
- 通常情况下,成员方法都使用public关键字修饰,成员变量都使用private关键字修饰。
final关键字修饰类和方法的作用
- final本意为"最终的、不可改变的",可以修饰类、成员方法以及成员变量。
使用方式:
final关键字修饰类体现在该类不能被继承。
-主要用于防止滥用继承,如:java.lang.String类等。
final关键字修饰成员方法体现在该方法不能被重写但可以被继承。
-主要用于防止不经意间造成重写,如:java.text.Dateformat类中format方法等。
final关键字修饰成员变量体现在该变量必须初始化且不能改变。
-主要用于防止不经意间造成改变,如:java.lang.Thread类中MAX_PRIORITY等
常量的概念
-
在以后的开发中很少单独使用final关键字来修饰成员变量,通常使用
public static final关键字共同修饰成员变量来表达常量的含义,常量的命
名规范要求是所有字母都要大写,不同的单词之间采用下划线连接。 -
public static final double PI = 3.14;
错题集
1、关于final关键字描述错误的是( A B C D ) (多选题)
A、final关键字修饰类表示可以被继承
B、final关键字修饰方法不能被继承
C、final关键字修饰成员变量不能初始化
D、final关键字修饰成员变量可以被赋值
解析:A、final关键字修饰类不可以被继承
B、final修饰方法不能被重写,但可以被继承
C、final修饰成员变量必须初始化并且不能改变
D、final修饰成员变量初始化后不可再修改城院变量的值
2、关于构造块和静态代码块的说法正确的是 ( C、D ) (多选题)
A、构造块就是在方法一中使用一堆花括号括起来的代码块。
B、构造块是在构造方法调用结束后执行的。
C、静态代码块会随着类的加载而准备就绪并执行。
D、每创建一个对象就会执行一次构造块。
解析:构造块:在类体中直接用{} 括起来的代码块。 不可用中文"花括号"代替
总结
-
static关键字
概念、使用方式、构造块和静态代码块、单例设计模式、
-
继承
概念、特点、方法的重写、重写的原则等
-
访问控制
public、private、package、静态导入等
-
final关键字
概念、修饰类、成员方法、成员变量、常量等
多态和特殊类
多态的概念
-
多态主要指同一种事务表现出来的多种形态。
-
饮料:可乐、雪碧、红牛、脉动、…
-
宠物:猫、狗、鸟、小强、鱼、…
-
人:学生、教师、工人、保安、…
-
图形:矩形、圆形、梯形、三角形、…
多态的语法格式:
- 父类类型 引用变量名 = new 子类类型();
- 如:
Shape sr = new Rect();
sr.show();
多态的特点
-
当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调
用父类独有的方法。 -
当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接
调用子类独有的方法。 -
对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段
调用子类重写的版本(动态绑定)。 -
对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
引用数据类型之间的转换
- 引用数据类型之间的转换方式有两种:自动类型转换 和 强制类型转换。
- 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也
叫做向上转型。 - 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也
叫做向下转型或显式类型转换。 - 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
- 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运
行阶段发生类型转换异常。 - 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
多态的意义
- 多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的
效果。
抽象方法的概念
-
抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就
是没有方法体。 -
具体格式如下:
访问权限 abstract 返回值类型 方法名(形参列表);
public abstract void cry();
抽象类的概念
- 抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象。
抽象类和抽象方法的概念
- 抽象类中可以有成员变量、构造方法、成员方法;
- 抽象类中可以没有抽象方法,也可以有抽象方法;
- 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并使用abstract修饰的类。
抽象类的实际意义
-
抽象类的实际意义不在于创建对象而在于被继承。
-
当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,
因此叫做模板设计模式。
笔试考点
// private 和 abstract 关键字不能共同修饰一个方法
// private是私有的,私有的类不能被继承
private abstract double getLixi();
// final 和 abstract 关键字不能共同修饰一个方法
// final修饰的方法是不能被重写的,而抽象方法是必须要重写才能使用
public final abstract double getLixi();
// static 和 abstract 关键字不能共同修饰一个方法
// static关键字会把方法会自动提升为类级别,可以通过类名.方法名调用,但抽象方法不能new对象,所以不能共存
public static abstract double getLixi();
接口的基本概念
- 接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法。
- 定义类的关键字是class,而定义接口的关键字是interface。
- 如:金属接口 货币接口 黄金类
public interface Interface1 {
//java9新特性,接口中允许有私有方法
/*public static final*/ int CNT = 1; //接口中只能有常量
private void show() { }
/*public abstract*/ void show2();//接口中只能有抽象方法(新特性除外),注释中的新特性可以省略,但建议写上
}
类和接口之间的关系
抽象类和接口的主要区别(笔试题)
- 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
- 继承抽象类的关键字是extends,而实现接口的关键字是implements。
- 继承抽象类支持单继承,而实现接口支持多实现。
- 抽象类中可以有构造方法,而接口中不可以有构造方法。
- 抽象类中可以有成员变量,而接口中只可以有常量。
- 抽象类中可以有成员方法,而接口中只可以有抽象方法。
- 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需
要重写(Java8以前的版本)。 - 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非
抽象方法需要使用default关键字修饰。 - 从Java9开始增加新特性,接口中允许出现私有方法。
/*增加非抽象方法 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非
抽象方法需要使用default关键字修饰。*/
public default void show1() {
System.out.println("这里仅仅是接口中的默认功能,实现类可以自由选择是否重写!");
}
//增加静态方法 隶属于类层级,也就是接口层级
public static void test() {
System.out.println("这里是静态方法,可以直接通过接口名.的方式调用,省略对象的创建");
}
随堂测试
总结
-
多态(重中之重)
基本概念、语法格式、多态的特点、类型转换、instanceof、实际意义等
-
抽象类(重点)
抽象方法、抽象类、抽象类和抽象方法的关系、实际意义等
-
接口(重点)
基本概念、常量、抽象方法、弥补不能多继承的不足、接口和类之间的关系、抽象类和接口的主要区别等。
特殊类
内部类的概念和分类
- 当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类
(Inner),而这个内部类所在的类叫做外部类(Outer)。 - 类中的内容:成员变量、成员方法、构造方法、静态成员、构造块和静
态代码块、内部类。
实际作用
- 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个
类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以
方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
内部类的分类
- 普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
- 静态内部类 - 使用static关键字修饰的内部类,隶属于类层级。
- 局部内部类 - 直接将一个类的定义放在方法体的内部时。
- 匿名内部类 - 就是指没有名字的内部类。
普通(成员)内部类的格式
- 访问修饰符 class 外部类的类名 {
访问修饰符 class 内部类的类名 {
内部类的类体;
}
}
public class InnerClass {
private int cnt = 1;
public class InnerClass2{
int ia = 4;
int cnt = 2;
public InnerClass2(){
System.out.println("普通内部类中的构造方法");
}
public void show1(int cnt){
System.out.println("ia = " + ia); //4
System.out.println("内部类show方法中的cnt数值为:" + cnt); //5
System.out.println("内部类中成员变量cnt数值为:" + this.cnt); //2
System.out.println("外部类中的cnt数值为:" + InnerClass.this.cnt); //1
}
}
}
普通内部类的使用方式
-
普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
-
普通内部类和普通类一样可以使用final或者abstract关键字修饰。
-
普通内部类还可以使用private或protected关键字进行修饰。
-
普通内部类需要使用外部类对象来创建对象。
-
如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使
用this关键字。
public class InnerClassTest {
public static void main(String[] args) {
//创建外部类对象
InnerClass ic = new InnerClass();
InnerClass.InnerClass2 ic1 = ic.new InnerClass2();
ic1.show1(5);
}
}
静态内部类的格式
- 访问修饰符 class 外部类的类名 {
访问修饰符 static class 内部类的类名 {
内部类的类体;
}
}
public class StaticOut {
private int cnt = 1; //隶属于对象层级
private static int snt = 3; //隶属于类层级
public static void show() {
System.out.println("外部类的show方法");
}
public static class StaticInner {
private int ia = 4;
private static int snt = 4;
public StaticInner(){
System.out.println("静态内部类中的构造方法");
}
public void show1(){
System.out.println("ia = " + ia); //4
System.out.println("外部类中的snt数值为:" + snt); //3
//System.out.println("外部类中cnt的值为:" + cnt); //error:静态上下文中不能访问非静态的成员,因此此时可能还没有创建对象
}
public void show2(int snt) {
System.out.println("snt = " + snt); //5
System.out.println("静态内部类的snt = " + StaticInner.snt); //4
System.out.println("外部类的snt = " + StaticOut.snt); //3
//StaticOut.show(); //方法一使用类名.的方式访问
new StaticOut().show(); //方法二访问外部类普通方法
}
}
}
静态内部类的使用方式
- 静态内部类不能直接访问外部类的非静态成员。
- 静态内部类可以直接创建对象。
- 如果静态类内部访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
public class StaticOutTest {
public static void main(String[] args) {
//声明StaticInner类型的引用指向该类型的对象
StaticOut.StaticInner st = new StaticOut.StaticInner();
st.show1();
System.out.println("-------------------------------");
st.show2(5);
}
}
局部(方法)内部类的格式
- 访问修饰符 class 外部类的类名 {
访问修饰符 返回值类型 成员方法名(形参列表) {
class 内部类的类名 {
内部类的类体;
}
}
}
public class AreaOuter {
private int cnt = 1;
//定义一个局部变量进行测试,从Java8开始默认理解为final关键字修饰的变量
//虽然可以省略final关键字,但建议加上,final修饰的变量不可被赋值,由局部内部类和局部变量的声明周期不同导致。
final int ic = 4;
//定义局部内部类,只在方法体的内部好使
public void show() {
class AreaInner {
private int ia = 2;
public AreaInner(){
System.out.println("局部内部类的构造方法");
}
public void test() {
System.out.println("ia = " + ia); //2
System.out.println("cnt = " + cnt); //1
}
}
AreaInner ai = new AreaInner();
ai.test();
}
}
局部内部类的使用方式
- 局部内部类只有在该方法的内部可以使用。
- 局部内部类可以在方法体内部直接创建对象。
- 局部内部类不能使用访问控制符和static关键字修饰符。
- 局部内部类可以使用外部方法的局部变量,但必须是final的。由局部内部类和局部变量的声明周期不同导致。
public class AreaOuterTest {
public static void main(String[] args) {
AreaOuter ao = new AreaOuter();
ao.show();
}
}
回调模式模式的概念
-
回调模式是指---------如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;
而该方法在运行时会调用到参数对象所实现的方法(接口中定义的)。
//我把我的对象传给你,你根据我的对象又回来调用我内部的方法,这就叫回调模式
public interface AnonymousInterface {
//自定义抽象方法
public abstract void show();
}
public class AnonymousInterfaceImpl implements AnonymousInterface {
@Override
public void show() {
System.out.println("这里是接口的实现类");
}
}
public class AnonymousInterfaceTest {
//AnonymousInterface ai = new AnonymousInterfaceImpl();
//接口类型的引用指向实现类型的对象,形成了多态
public static void test(AnonymousInterface ai){
//编译调用父类版本,运行调用实现类重写的版本
ai.show();
}
public static void main(String[] args) {
AnonymousInterfaceTest.test(new AnonymousInterfaceImpl());
}
}
匿名内部类的语法格式(重点)
- 接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
用法:
- 当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
- 自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
- 使用上述匿名内部类的语法格式得到接口/类类型的引用即可;
//从Java8开始提出新特性lamda表达式可以简化上述代码,格式为:(参数列表) -> {方法体}
AnonymousInterface ait2 = () -> System.out.println("lamda表达式原来如此简单");
枚举
枚举的基本概念
- 一年中的所有季节:春季、夏季、秋季、冬季。
- 所有的性别:男、女
- 键盘上的所有方向按键:向上、向下、向左、向右。
- 在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事
物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类
型。
枚举的定义
- 使用public static final表示的常量描述较为繁琐,使用enum关键字来定
义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。 - 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public
static final关键字共同修饰,因此采用枚举类型.的方式调用。 - 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public
static final关键字共同修饰,因此采用枚举类型.的方式调用。 - 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默
认也是私有的。
Enum类的概念和方法
- 所有的枚举类都继承自java.lang.Enum类,常用方法如下:
枚举类实现接口的方式
- 枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写。
注解(重点)
- 注解(Annotation)又叫标注,是从Java5开始增加的一种引用数据类型。
- 注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、
以及运行时执行指定的处理。
注解的语法格式
- 访问修饰符 @interface 注解名称 {
注解成员;
} - 自定义注解自动继承java.lang.annotation.Annotation接口。
- 通过@注解名称的方式可以修饰包、类、 成员方法、成员变量、构造方
法、参数、局部变量的声明等。
注解的使用方式
-
注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方
法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该
成员变量的类型。 -
如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八
种基本数据类型、String类型、Class类型、enum类型及Annotation类型。
//若一个注解中没有任何的成员,则这样的注解叫做标记注解,标识注解
public @interface MyAnotation {
public String value() default "123"; //声明一个String类型的成员变量,名字为value
public String value2();
}
//表示将标签MyAnotation贴在Person类的代码中,使用注解时 成员参数名 = 成员参数值,...
//@MyAnotation(value = "张三",value2 = "李四")
@MyAnotation(value2 = "李四") //注解声明了默认值,可以省略不写
public class Person {
private String name;
private int age;
}
元注解的概念
- 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但
是它能够应用到其它的注解上面。 - 元注解主要有 @Retention、@Documented、@Target、@Inherited、
@Repeatable。
元注解@Retention
- @Retention 应用到一个注解上用于说明该注解的的生命周期,取值如下:
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时
它将被丢弃忽视。 - RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加
载到 JVM 中,默认方式。 - RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载
进入到 JVM 中,所以在程序运行时可以获取到它们。
@Retention(RetentionPolicy.SOURCE) //表示此注解在源代码中有效
@Retention(RetentionPolicy.CLASS) //表示此注解在字节码文件中有效(javac编译后有效),默认有效
@Retention(RetentionPolicy.RUNTIME) //表示此注解在运行时有效
什么时候用取决于业务需求
元注解@Documented
- 使用javadoc工具可以从程序源代码中抽取类、方法、成员等注释形成一
个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容。 - @Documented用于指定被该注解将被javadoc工具提取成文档。
- 定义为@Documented的注解必须设置Retention值为RUNTIME。
元注解@Target
- @Target用于指定被修饰的注解能用于哪些元素的修饰,取值如下:
//表示下面的注解可以用于类型、构造方法、成员变量、成员方法、参数的描述
@Target({ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
元注解@Inherited
- @Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标
记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继
承超类的注解。
元注解@Repeatable
- @Repeatable表示自然可重复的含义,从Java8开始增加的新特性
- 从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
- 其中ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明
语句中,如:泛型。 - 其中ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
常见的预制注解
- 预制注解就是Java语言自身提供的注解,具体如下:
总结
-
内部类
概念、普通内部类、静态内部类、局部内部类、匿名内部类、回调模式等
-
枚举类型
概念、自定义枚举、enum关键字、继承enum类、实现接口等
-
注解
概念、自定义注解、使用、元注解、预制注解等
错题解析
第5题答案为RetentionPolicy.SOURCE 没有S
棋盘打印思路:
1.自定义二维数组来描述棋盘,默认初始值为0
2.先绘制棋盘中第一行的坐标信息,也就是列坐标信息
tion(RetentionPolicy.RUNTIME) //表示此注解在运行时有效
什么时候用取决于业务需求
#### 元注解@Documented
- 使用javadoc工具可以从程序源代码中抽取类、方法、成员等注释形成一
个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容。
- @Documented用于指定被该注解将被javadoc工具提取成文档。
- 定义为@Documented的注解必须设置Retention值为RUNTIME。
#### 元注解@Target
- @Target用于指定被修饰的注解能用于哪些元素的修饰,取值如下:
[外链图片转存中...(img-RS3jyRls-1589009946558)]
```java
//表示下面的注解可以用于类型、构造方法、成员变量、成员方法、参数的描述
@Target({ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
元注解@Inherited
- @Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标
记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继
承超类的注解。
元注解@Repeatable
- @Repeatable表示自然可重复的含义,从Java8开始增加的新特性
- 从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
- 其中ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明
语句中,如:泛型。 - 其中ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
常见的预制注解
- 预制注解就是Java语言自身提供的注解,具体如下:
总结
-
内部类
概念、普通内部类、静态内部类、局部内部类、匿名内部类、回调模式等
-
枚举类型
概念、自定义枚举、enum关键字、继承enum类、实现接口等
-
注解
概念、自定义注解、使用、元注解、预制注解等
错题解析
第5题答案为RetentionPolicy.SOURCE 没有S
棋盘打印思路:
1.自定义二维数组来描述棋盘,默认初始值为0
2.先绘制棋盘中第一行的坐标信息,也就是列坐标信息
3.绘制棋盘中除了第一行之外的其他部分以及行坐标信息 使用双重for循环外层打印每行第一个信息,内层打印“+” 打印完换行