一、面向过程和面向对象
1.1、面向过程
强调的是我该怎么去做。即功能的执行过程,即先干啥,后干啥。在面向过程中,我们会写很多的函数,每一个函数负责完成某一个功能。
而一个主函数里面有多个小函数,需要完成某个功能的时候依次调用即可
由此我们发现面向过程的设计思想存在以下几个缺陷:系统软件适应性差,可拓展性差,维护性低。
1.2、面向对象
一种基于面向过程的新的编程思想,顾名思义该思想是站在对象的角度思考问题,我们把多个功能合理的放到不同对象里,强调的是我该让谁来做
面向对象最小的程序单元是类,必须先存在类的定义,再有对象,而具备某种功能的实体,称为对象
面向过程和面向对象的差别如下:
面向过程和面向对象各有千秋,面向对象更符合我们常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性,它拥有三大特征:
- 封装
- 继承
- 多态
二、变量
2.1、变量的分类
根据变量定义的位置的不同,我们大致可以把变量分为两大类:
- 成员变量:直接定义在类中,方法的外面,又称之为字段,不是属性
- 局部变量:除了成员变量外,其他变量都是局部变量,仅仅存在于方法内、代码块、方法的形式参数中
2.2、变量的初始值
变量的初始化表示在内存中开辟一个存储空间进行存储,只有初始化后才可以使用,不同的变量类型初始值不同
成员变量
默认是有初始值的,不同类型的初始值不同
数据类型 | 初始的默认值 |
---|---|
byte、short、int、long | 0 |
float、double | 0.0 |
char | 一个空字符(空格) “\u0000” |
boolean | false |
引用数据类型 | null(表示不引用任何对象 |
局部变量
局部变量没有初始值,必须手动初始化才可以使用
2.3、变量的作用域
变量根据定义的位置不同,也决定了各自的作用域是不同的,关键是看变量所在的花括号的位置
成员变量
在所定义的类中都有效
局部变量
从开始定义的位置到花括号内有效,花括号外就无效了
2.4、变量的生命周期
变量的生命周期,通俗的来说就是变量在内存中可以存活多久
成员变量
成员变量是属于对象的,对象在堆内存中,所以成员变量也是存储在堆内存中的,随着对象的1消亡而消亡
局部变量
局部变量是存储在栈内存的,随着方法的调用的结束而消亡
局部变量是存储在方法中的,每次调用方法都会在栈空间开辟一个内存空间,我们成为栈帧,方法1调用结束,栈帧就被销毁了,内存中存储的变量数据也就销毁了
三、类
3.1、类的定义
类是拥有相同特性(状态)和行为(功能)的多个对象的抽象
- 使用成员变量来表示状态
- 使用成员方法来表示行为
格式
public class 类名{
//可编写0到N个成员变量
修饰符 数据类型 变量名1;
修饰符 数据类型 变量名2;
//可编写0到N个成员方法
修饰符 返回值类型 方法名称(参数){
//方法体
}
}
注意:
- 成员方法和变量都不可以用static修饰,修饰符不是必须的
- 在描述对象的类中,不需要定义main方法,main方法在专门的测试类中编写,切测试类和描述对象的类是分开编写的
四、对象
4.1、对象的创建
类名 对象遍历名 = new 类名();
如果我们直接打印对象的话,打印的是类似数组地址的hashCode值
4.2、匿名对象
创建对象之后没有赋值给某个遍历,只能使用一次
new 类名();
4.3、给字段设置数据
对象变量名.字段名 = 值;
4.4、获取字段的数据
数据类型 变量 = 对象变量.字段名;
4.5、对象调用方法
对象变量名.方法(参数);
4.6、对象实例化的内存分析
以下面简单地Cat类进行分析
public class Cat(){
String name;
int age;
}
创建对象
Cat cat = new Cat();
此时如果通过查看对象的name和age属性可以发现分别为初始值null和0
给对象赋值
cat.name="xiaolin";
cat.age=18;
对象调用方法
public class Cat(){
String name;
int age;
public void say(){
System.out.println("我们一起学猫叫");
}
}
五、构造器(构造方法)
5.1、构造器的定义
构造器,也称之为构造方法(Constructor),作用是用来创建对象和给对象做初始化操作,只能在创建对象的时候使用一次
构造器的语法
public 类名(参数){
//方法体
}
//示范:
public class Cat {
public Cat() {
}
//省略其他代码
}
构造器的特点
- 构造器名称和类名相同
- 不能定义返回类型
- 构造器中不能出现return语句
5.2、默认构造器
我们在创建类的时候,没有手动写构造器,而没有报错,原因是因为如果我们在编写对象的时候,如果没有写构造器的话,编译器会在编译源文件的时候,自动创建一个默认构造器,默认构造器的特点:无参数、无方法体。
如果类使用了public修饰,那么他默认的构造器也会使用public修饰,反之亦然
5.3、构造器的使用
没有构造器之前
之前,我们是先通过一个默认参数构造器,先创建出一个对象再初始化(给字段设置值)
Cat cat = new Cat();
c.name = "xialin";
c.age = 18;
有了构造器之后
有了构造器之后,可以直接通过构造器同时完成对象创建和初始化操作
public class Cat {
String name;
int age;
public Cat(String name, int age) {
this,name = name;
this.age = age;
}
void say() {
System.out.println("我是" + name + ",今年" + age + "岁");
}
}
Cat cat = new Cat("zs", 19);
cat.say();
Cat cat = new Cat(); // 此行报错
当自己定义出构造器之后,编译器不再创建默认的构造器了,所以就不再自动有无参构造器,我们一般在开发中无参构造器和有参构造器会同时编写,他们构成重载关系
public class Cat {
String name;
int age;
//无参数构造器
public Cat() {
}
//带参数构造器
public Cat(String name, int age) {
this,name = name;
this.age = age;
}
//其他代码
}
六、封装
封装是面向对象三大特征之一,其含义有两个(掌握思想):
-
把对象的字段和方法存放在一个独立的模块中(类)
-
信息隐藏,尽可能隐藏对象的数据和功能的实现细节
封装的好处:
- 保证数据的安全性,防止调用者随意修改数据
- 提高组件的重用性,把公用功能放到一个类中,谁需要该功能,直接调用即可
限制字段不能够随意修改的利器就是访问修饰符
6.1、访问修饰符
访问修饰符,决定了有没有权限访问某个资源,封装的本质就是要让有些类看不到另外一些类中定义的字段和方法。Java提供了不同的访问权限修饰符来限定类中的成员让谁可以访问到
修饰符 | 类的内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | √ | |||
无 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
- private:表示当前类是私有的,只能在本类中访问,离开本类之后就不能直接访问
- 不写:表示当前包私有,定义和调用只能在同一个包中,才能访问
- protected:表示子类访问权限,同一个包的可以访问,即使不同包但是有继承关系也是可以访问的
- public:表示公共的,可以在当前项目的任何地方访问
一般在开发中都是提供私有属性,暴露公有的访问方法
6.2、JavaBean规范
JavaBean是一种某些符合条件的特殊类,但是必须遵循一定的规范:
- 类必须使用public修饰
- 必须保证有公共无参数构造器,即使手动提供了带参数的构造器,也得手动提供无参数构造器
- 段使用private修饰,每个字段提供一对getter和setter方法
public String getName(){
return name; //返回name字段存储的值
}
public void setName(String n){
name = n; //把传过来的参数n的值,存储到name字段中
}
6.3、构造器和setter方法
构造器和setter方法都可以给对象设置数据:
-
构造器,在创建对象的时候设置初始数据,只能初始化一次。
-
setter方法,创建对象后再设置初始数据,可以设置多次。
七、继承
面向对象的继承思想,可以解决多个类存在共同代码的问题
-
被继承的类,称之为父类、基类
-
继承父类的类,称之为子类,拓展类
-
父类:存放多个子类共同的字段和方法
-
子类:存放自己特有的字段和方法
7.1、继承的语法
在程序中,如果一个类需要继承另一个类,此时使用extends关键字
public class 子类名 extends 父类名{
}
注意:Java中类只支持单继承,不支持多继承,但是支持多重继承。也就是说一个子类只能有一个直接的父类,父类也可以再有父类。一个父类也可以有多个子类
class Student1();
class Student2();
class Student extend Student1,Student2(){}//错误
Object类是Java语言的根类,任何类都是Object的子类,要么是直接子类,要么是间接子类
7.2、子类可以继承到父类哪些成员
子类继承父类之后,可以拥有到父类的某一些成员(字段和方法),根据访问修饰符来判断:
- 父类中用public和protected修饰的成员,子类均可以继承
- 如果父类和子类在同一个包中,使用缺省访问修饰的成员,此时子类可以继承到
- 如果父类中的成员用private修饰,子类继承不到,因为private只能在奔本类中访问
- 父类的构造器,子类也无法继承,因为构造器必须和类名相同
7.3、方法的重写
当子类存在一个和父类一模一样的方法时,我们就称之为子类覆盖了父类的方法,也称之为重写。那么我们就可以在子类方法体中,重写编写逻辑代码
方法调用的顺序为:通过对象调用方法时,先在子类中查找有没有对应的方法,若存在就执行子类的,若子类不存在就执行父类的,如果父类也没有,报错。
方法重写需要注意的点:
- private修饰的方法不能被子类所继承,也就不存在重写的概念
- 实例方法签名必须相同(方法签名=方法名+方法参数列表)
- 子类方法的返回值类型和父类的返回值类型相同或者是其子类
- 子类方法中声明抛出的异常小于或者等于父类方法声明抛出的异常类型
- 子类方法的访问权限比父类的访问权限更大或者相等
- 一般开发都是直接拷贝父类的方法定义粘贴到子类中,重新编写子类的方法体
7.4、super关键字
在子类中的某一个方法中需要去调用父类中被覆盖的方法,此时得使用super关键字。
如果调用被覆盖的方法不使用super关键字,此时调用的是本类中的方法。super关键字表示父类对象的意思
7.5、抽象
抽象方法用abstract来修饰方法,被abstract修饰的方法具备两个特征:
- 该方法没有方法体
- 要求子类必须覆盖该方法
7.5.1、抽象方法
使用abstract修饰的方法,称为抽象方法
public abstract 返回类型 方法名(参数);
抽象方法的特点:
- 使用abstract修饰,没有方法体,留给子类去覆盖
- 抽象方法必须定义在抽象类或者接口中
7.5.2、抽象类
使用abstract修饰的类,称为抽象类
public abstract class 类名{
}
抽象类的特点:
- 抽象类不能创建对象,调用没有方法体的抽象方法没有任何意义
- 抽象类中可以同时拥有抽象方法和普通方法
- 抽象类必须有子类才有意义,子类必须覆盖父类的抽象方法,否则子类也得作为抽象类
7.6、Object类和常用方法
Object本身表示对象的意思,是Java中的根类,要么是一个类的直接父类,要么就是一个类的间接父类。任何类都直接(间接)继承了Object类
class A{}
//等价于
class A extends Object{}
因为所有类都是Object类的子类, 所有类的对象都可以调用Object类中的方法,经常使用的方法有
7.6.1、boolean equals(Object obj)
boolean equals(Object obj):拿当前调用该方法的对象和参数obj做比较
在Object类中的equals方法和“ == ”符号相同,都是比较对象是否是同一个的存储地址。
public class ObjectDemo {
public static void main(String[] args) {
//创建Person对象p1
Person p1 = new Person();
//创建Person对象p2
Person p2 = new Person();
//比较p1和p2的内存地址是否相同
boolean ret1 = p1 == p2;
boolean ret2 = p1.equals(p2);
System.out.println(ret1); //false
System.out.println(ret2); //false
}
}
7.6.2、toString方法
toString表示把对象中的字段信息转换为字符串格式
打印对象其实就是打印对象的toString()方法,但是toString()方法默认打印的是对象的hashCode的值
com._04_object.Person@15db9742
所以一般我们都会重写toString()方法
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
7.7、== 符号详解
每一次使用new关键字,都表示在堆内存中创建一块新的内存空间
- 如果是基本数据类型:比较的是两个值是否相等
- 如果是对象数据类型:比较的是是否为同一块内存地址
八、多态
8.1、接口
接口是一种约定规范,是多个抽象方法的集合。仅仅只是定义了应该有哪些功能,本身不实现功能,至于每个功能具体怎么实现,就交给实现类完成。
接口中的方法是抽象方法,并不提供功能实现,体现了规范和实现相分离的思想,也体现了组件之间低耦合的思想。接口仅仅提供方法的定义,却不提供方法的代码实现
所谓耦合度,表示组件之间的依赖关系。依赖关系越多,耦合性越强,同时表明组件的独立性越差,在开发中往往提倡降低耦合性,可提高其组件独立性,举一个很简单的例子:
- 集成显卡:显卡和主板焊死在一起,显卡坏了,只能换主板
- 独立显卡:显卡和主板相分离,显卡插到主板上即可,显卡坏了,只换显卡,不用换主板
8.1.1、接口的定义
接口可以认为是一种特殊的类,但是定义类的时候使用class关键字,定义接口使用interface关键字,接口中的方法都是公共的抽象方法
public interface 接口名{
//抽象方法1();
//抽象方法2();
//抽象方法2();
}
注意:从Java 8开始, Java支持在接口中定义有实现的方法
public interface IMan {
public abstract void walk();//抽象方法
default void defaultMethod(){
System.out.println("有默认实现的方法, 属于对象");
}
static void defaultMethod(){
System.out.println("有默认实现的方法, 属于类");
}
}
类可以继承类,但是只能单继承的,接口也可以继承接口,但是却可以继承多个接口,也就是说一个接口可以同时继承多个接口
8.1.2、接口实现类
和抽象类一样,接口是不可以创建对象的,如果想实现接口的功能,就必须定义一个类去实现接口,并且覆盖接口中的所有方法,这个类称为实现类,这种类和接口的关系称为实现关系
public class 类名 implements 接口名{
//覆盖接口中抽象方法
}
-
接口:定义多个抽象方法,仅仅定义有哪些功能,不做任何实现
-
实现类:实现接口,重写接口中的抽象方法,完成具体功能的实现
8.2、多态
在继承关系,是一种”is A”的关系,也就说子类是父类的一种特殊情况
public class Animal{}
public class Dog extends Animal{}
public class Cat extends Animal{}
此时我们可以认为猫和狗都是一种特殊动物,那么可以使用动物类型来表示猫或者狗
Dog dog = new Dog(); //创建一只狗对象,赋给子类类型变量
Animal animal = new Cat(); //创建一只猫对象,赋给父类类型变量
此时对象animal具有两种类型:
- 编译类型:声明对象时候的类型(Animal)
- 运行类型:对象真实的类型(Cat)
当编译类型和运行类型不一致的时候,多态就产生了
所谓的多态就是表示一个对象有多种形态,简单来说就是同一引用类型,由于引用的实例不同,对同一方法产生的结果也不同
Person person = null;
person = new Man(); //person此时表示Man类型
person = new Woman();//person此时表示Woman类型
多态一定建立在方法重写或者实现之上,可以是继承关系(类和类),也可以是实现关系(接口和实现类),在开发中,一般都指接口和实现类之间的关系,多态在在开发中有两种定义格式
8.2.1、操作继承关系(开发中不是很多)
父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法
父类 变量名 = new 子类();
变量名.方法();
Animal类:
public class Animal {
public void shout() {
System.out.println("动物...叫...");
}
}
Cat类:
public class Cat extends Animal{
public void shout() {
System.out.println("猫叫...");
}
}
Test类:
public class AnimalDemo{
public static void main(String[] args){
Animal animal = new Cat();
animal.shout();
}
}
运行结果:
猫叫
8.2.2、操作实现关系
接口 变量名 = new 实现类();
变量名.方法();
ISwimable 接口:
public interface ISwimable{
void swim();
}
Fish类:
public class Fish implements ISwimable{}
public void swim(){
Sysout.out.println("鱼在游")
}
}
Test类:
public class Fish implements{
public static void main(String[] args){
ISwimable fish = new Fish();
fish.swim();
}
}
结果:
鱼在游泳
8.2.3、多态中方法调用问题
如果我们把子类对象赋值给父类对象
Animal animal = new Cat();
animal.shout();
那么animal对象在调用shout方法的时候,他调用的是子类自己的方法还是父类的方法呢?
我们可以看得出,在编译时期,JVM会先去找父类的方法,如果找到了就去找子类的同名方法,如果子类也有就运行子类的方法,否则就运行父类的方法,如果连父类的方法都没有找到的话,直接编译失败失败
8.2.4、类型转换和instanceof运算符
8.2.4.1、自动类型转换
自动类型转换:把子类对象赋给父类变量(多态)
Animal a = new Dog();
Object obj = new Dog(); //Object是所有类的根类
8.2.4.2、强制类型转换
把父类类型对象赋给子类类型变量(前提:该对象的真实类型应该是子类类型)
当需要调用子类特有的方法时,必须经过强制类型转换,不过有一个要求:父类必须是真实的子类类型才可以转换
Animal a = new Dog();
Dog d = (Dog) a;//正确
Cat c = (Cat) a;//错误,真实类型为Dog
8.2.4.3、instanceof 运算符
判断该对象是否是某一个类的实例
语法格式
boolean b = 对象A instanceof 类B; //判断 A对象是否是 B类的实例?如果是,返回true
8.2.4.4、多态总结
面向接口编程,体现的就是多态,其好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之间的实现差异,从而可以做到通用编程
8.3、面试题
接口和抽象类的区别
- 接口中所有的方法隐含的都是抽象的,但是抽象类中可以同时包含抽象方法和普通方法以及静态常量
- 类可以实现很多个接口,但是只能继承一个抽象类
- 类如果要实现一个接口,那么他必须要实现接口声明的所有方法,但是类可以不实现抽象类中的所有方法,但是这个类必须是抽象类
- 接口中不存在构造方法,因为接口的成员变量都是static final变量,是在编译的时候就完成了初始化操作了,无需通过构造方法来进行初始化操作,而抽象类必须有构造方法
- 抽象类和接口的概念的区别:
- 抽象类是从一些类中抽取他们的共有的属性,方法的修饰符可以是public或者是protected以及缺省,抽象类注重对类本身的抽象,抽象方法没有方法体,仅仅是声明了该方法,让继承他的子类去实现
- 接口主要是对类的行为抽象,接口也可以有变量和方法,但是变量以及方法的修饰符必须是public static final(缺省时会默认加上)和public abstract(缺省时默认也是这个)
九、关键字(this、super)
9.1、this关键字
this
关键字表示当前对象(谁调用this所在的方法,this就是哪一个对象主要)存在于两个位置:
- 在构造器中:表示当前创建的对象
- 在方法中:哪一个对象调用this所在的方法,此时this就表示哪个对象
什么时候需要使用this关键字
- 为了解决局部变量和成员变量之间的二义性,此时必须使用
- 同一个类中非static方法之间的互相调用,此时可以省略,但是基本不会省略
- 调用本类其他的构造方法
public class Dog {
private String name;
private int age;
public Dog() {
}
public Dog(String name) {
this(name, 0);// 调用两个参数的构造器(构造器之间的重载),必须放在构造器第一行
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public void say() {
String name = "局部变量";
System.out.println(name); // 访问局部变量
System.out.println(this.name);// 访问成员变量
this.other();// 调用当前类中非static方法
}
public void other() {
System.out.println(this.age);//此时的this是谁
}
}
this内存图
this关键字表示当前对象本身,一般用于类的内部,其内部存在一个地址,指向当前初始化对象本身
当new一个对象的时候,实际上产生了两个引用,一个是供Dog内部调用其他成员变量或者成员方法的this关键字,另一个是供外界程序调用实例成员的dog持有类信息
9.2、super关键字
super表示当前对象的父类对象,在创建子类对象的时候,在子类构造器的第一行会先调用父类的构造器
super虽然表示父类对象,但是他仅仅只是一个关键字,内部并没有地址,所以不能够引用
什么时候使用super
- 访问父类中非私有的实例方法,此时必须使用super
- 在子类的构造器中,调用父类的构造器,此时必须使用super
- 如果想访问父类的非私有成员变量,此时必须使用super
父类:
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void doWork() {
System.out.println("Person...doWork...");
}
}
子类:
public class Student extends Person {
private String sn;
public Student(String sn) {
super();// 隐式调用父类无参数构造器,必须作为构造第一行
this.sn = sn;
}
public Student(String name, int age, String sn) {
super(name, age);// 显示去调用父类有参数构造器,必须作为构造第一行
this.sn = sn;
}
public void doWork() {
super.doWork(); // 此时调用父类的doWork()方法
this.doWork(); // 此时调用自己的doWork()方法
System.out.println("Student...doWork...");
}
}
总结
- super调用构造方法必须写在子类构造方法的第一行
- 如果子类构造方法没有显示调用父类构造方法时,那么JVM会默认调用父类的无参构造器
十、修饰符(static、final)
10.1、static修饰符
static修饰的字段和方法都直接属于类,不属于该类的对象(字段和方法属于谁,就让谁来调用)
- 有static修饰的变量和方法:属于类,直接用类名调用即可,在同一个类中调用可以省略类名不写
- 没有static修饰的变量和方法:属于对象,必须先创建对象,然后用对象调用
注意:static方法不能使用super和this关键字
因为static是类级别的,super和this是对象级别的,存在类的时候不一定存在对象,也就说使用类名调用static方法时,此时可能是没有对象的。
10.1.1、静态方法
static修饰的方法称为静态方法,归类所有,也称为类方法
修饰符 static 返回值类型 方法名(形参列表){
}
静态方法有两种访问方式:
- 类名.静态方法名()√
- 对象.静态方法名()Java是不推荐这种访问机制的
静态方法的特性
- 静态方法中可以访问静态变量和其他静态方法
- 实例方法中可以访问静态成员变量以及静态成员方法
10.1.2、静态变量
在类中,用static关键字修饰的成员变量称为静态变量,归类所有,也称为类变量,类的所有实例对象都可以访问,被类的所有实例或者对象共享
static 数据类型 成员变量
静态变量的访问
-
类名.静态变量
-
类的对象.静态变量(Java不推荐)
10.2、final修饰符
final的含义是最终的,不可改变的,可以修饰类、方法、变量,他是来限制某个类不可以有子类,不可以覆盖方法
final修饰的类
表示最终的类,该类不可以再拥有子类
final public class Super {
}
public class Sub extends Super{ //此行语法报错
}
final修饰的方法
最终的方法,该方法不可以被子类覆盖
public class Super {
final public void doWork() {
}
}
public class Sub extends Super{
public void doWork() { //此行语法报错
}
}
final修饰的变量
表示常量,该变量只能赋值一次,不可以再重新赋值
- 基本数据类型:表示的值不能再改变
- 引用数据类型:所引用的地址不可以再改变
final int age = 17;
age = 100; //此行语法报错
final Dog d = new Dog();
d.setAge(5); //d的字段值是可以改变的
d = new Dog(); //此行语法报错
十一、代码块
直接使用{}括起来的一段代码区域,代码块里面的变量属于局部变量,仅在{}内有效
他有三种存在形式:普通代码块、构造代码块、静态代码块
11.1、普通代码块
直接定义在方法内部的代码块,一般的,不会直接使用局部代码块的,结合if、while、for等关键字使用,表示一块代码区域,作用域可以嵌套
public class CodeBlockDemo {
public static void main(String[] args) {
System.out.println("begin...");
{
//直接使用代码块,一般不用
int age = 17;
}
System.out.println(age); //此行报错,超出age作用范围,就不能访问到了
if (100 > 5) {
System.out.println("100 > 5");
}
System.out.println("end...");
}
}
11.2、构造代码块
构造代码块在类的内部,方法的外部,随着一个对象的创建而执行一次,在构造方法前执行
package day09_ObjectAdvanced.Classing.StaticBlock;
/**
* @author Xiao_Lin
* @version 1.0
* @date 2020/12/9 16:29
*/
public class Dog {
private String name;
static String age="111";
{
System.out.println("我是构造代码块");
}
public Dog(){
System.out.println("我是无参构造方法");
}
public Dog(String name){
System.out.println("我是有参构造方法");
}
public void shut(){
System.out.println("我是叫方法");
}
}
如果需要在构造方法执行前加载一些资源(如读配置文件、XML文件等等),我们可以把构造对象前的一切操作都放在构造代码块中执行
11.3、静态代码块
用static关键字所修饰的代码块称为静态代码块,位于类的内部、方法的外部,且只执行一次,在构造代码块、构造方法前执行
package day09_ObjectAdvanced.Classing.StaticBlock;
/**
* @author Xiao_Lin
* @version 1.0
* @date 2020/12/9 16:29
*/
public class Dog {
private String name;
static String age="111";
static {
System.out.println("我是静态代码块");
}
{
System.out.println("我是构造代码块");
}
public Dog(){
System.out.println("我是无参构造方法");
}
public Dog(String name){
System.out.println("我是有参构造方法");
}
public void shut(){
System.out.println("我是叫方法");
}
}
十二、内部类
12.1、类的组织方式
12.1.1、类和类的平行关系
一个文件可以定义多个类,但只能存在一个public类,且文件的名字和public类的名字要保持一致
public class Dog{
}
class Cat{
}
Dog和Cat地位一样,和分开定义两个文件是一模一样的
12.1.2、类和类之间包含关系
public class Outer {
public class Inner{
}
}
Outer和Inner是包含关系,Outer称为外部类,而Inner称为内部类,内部类Inner作为一个Outer的成员而存在
12.2、内部类的概述
什么是内部类,把一个类定义在另一个类的内部,把里面的类称之为内部类,把外面的类称之为外部类,内部类的分类有:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
12.3、匿名内部类
当一个类只使用一次,可以声明成匿名内部类
匿名内部类 必须有实现存在,多以实现接口居多
public class Outer {
public void print(){
/*
class Inner implements AInterface{
@Override
public void showInfo() {
System.out.println("inner.showInfo");
}
}
new Inner().showInfo();
*/
/*
AInterface aInterface = new AInterface(){
@Override
public void showInfo() {
System.out.println("inner.showInfo");
}
};
aInterface.showInfo();
*/
// 通过匿名类创建匿名对象
new AInterface(){
@Override
public void showInfo() {
System.out.println("inner.showInfo");
}
}.showInfo();
}
}
十三、枚举类
枚举是一种特殊的类,固定一个类只能有哪些对象
13.1、枚举类的定义
public enum 枚举类型{
常量对象A、常量对象B、常量对象C
}
publicc enum Story{
HISTORY、ENGLISH、MATH
}
我们自定义的枚举类都是在底层直接继承了 java.lang.Enum
类,枚举中都是全局公共的静态常量,可以直接用枚举类名调用
Stroy story = Story.ENGLISH;
因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法
String name = 枚举对象.name(); // 返回枚举对象的常量名称
int ordinal = 枚举对象.ordinal(); // 返回枚举对象的序号,从0开始
注意:枚举类不能使用创建对象