1.类和包
分类:分工协作,专人干专事。
分包:如果将所有的类文件都放在同一个包下,不利于管理和后期维护,所以,对于不同功能的类文件,可以放在不同的包下进行管理。
包:本质上就是文件夹(单级包、多级包)。
定义格式:package 包名;
- 包的命名规则:字母都是小写。
- 多级包之间使用
.
进行分割。
- 多级包的定义规范:公司的网站地址翻转(去掉 www),比如
com.baidu.其他的包名
。
- 一般情况下,我们不会手动地去给某一个类定义包,使用 IDEA 开发工具创建即可。
注意事项:
- package 语句必须是程序的第一条可执行的代码。
- package 语句在一个 .java 文件中只能有一个。
- 如果没有 package,默认表示无包名。
在同一个包下,类与类之间的访问不需要导包,直接使用即可。
在不同包下,类与类之间的访问有如下两种方式:
(1) import 导包后访问。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a277b005f04548e393e61b4e8d194a6f.png#pic_center)
(2) 通过全类名(包名 + 类名)访问。多个包下出现了相同的类名称可以使用全类名进行区分。
![在这里插入图片描述](https://img-blog.csdnimg.cn/3b2101f36f9c4707bc61f7e22ced0f55.png#pic_center)
注意:import、package、class 三个关键字的摆放位置存在顺序关系
- package 必须是程序的第一条可执行的代码
- import 需要写在 package 下面
- class 需要在 import 下面
2.static 关键字
static 关键字是静态的意思,是 Java 中的一个修饰符,可以修饰成员方法、成员变量。
- 被 static 修饰的成员变量一般叫做静态变量
- 被 static 修饰的成员方法一般叫做静态方法
(1) 被 static 修饰的成员会被该类的所有对象共享。
package com.qdu.test;
public class Student {
String name;
int age;
static String school;
public void show() {
System.out.println(name + "..." + age + "..." + school);
}
}
package com.qdu.test;
public class Test1Static {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
stu1.school = "qdu";
stu1.show(); // 张三...23...qdu
Student stu2 = new Student();
stu2.show(); // null...0...qdu
stu2.school = "hit";
stu1.show(); // 张三...23...hit
}
}
(2) 被 static 修饰的成员,多了一种调用方式,可以通过 类名.
调用,推荐使用 类名.
调用。
package com.qdu.test;
public class Test1Static {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
Student.school = "qdu";
stu1.show(); // 张三...23...qdu
Student stu2 = new Student();
stu2.show(); // null...0...qdu
Student.school = "hit";
stu1.show(); // 张三...23...hit
}
}
(3) 被 static 修饰的成员,会随着类的加载而加载,优先于对象存在。
package com.qdu.test;
public class Test1Static {
public static void main(String[] args) {
Student.school = "qdu";
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
stu1.show(); // 张三...23...qdu
Student stu2 = new Student();
stu2.show(); // null...0...qdu
}
}
(4) 静态方法只能访问静态的成员;非静态方法可以访问静态的成员,也可以访问非静态的成员。
(5) 静态方法中没有 this 关键字。
3.继承
3.1 继承的特点
![在这里插入图片描述](https://img-blog.csdnimg.cn/e2478f5422ff4959837330beb2d762c4.png#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/3e698cd9b8b849088d4b7151267854b6.png#pic_center)
继承:让类与类之间产生关系(子父类关系),子类可以直接使用父类中非私有的成员。
格式:public class 子类名 extends 父类名 { }
范例:public class Zi extends Fu { }
- Fu:是父类,也被称为基类、超类。
- Zi:是子类,也被称为派生类。
继承的好处:
- 提高了代码的复用性(多个类相同的成员可以放到同一个类中)。
- 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)。
- 让类与类之间产生了关系,是多态的前提。
继承的弊端:
- 继承是侵入性的。
- 降低了代码的灵活性。继承关系导致子类必须拥有父类非私有属性和方法,让子类自由的世界中多了一些约束。
- 增强了代码的耦合性。
代码与代码之间存在关联都可以将其称之为耦合。
![在这里插入图片描述](https://img-blog.csdnimg.cn/39c4131e496241e48652001177057898.png#pic_center)
问:什么时候使用继承?
答:当类与类之间存在相同(共性)的内容,并且产生了 is a 的关系,就可以考虑使用继承来优化代码。
is a 的关系,即谁是谁的一种。例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a5423ec3ba0e488c9130fad0f6bcd95f.png#pic_center)
Java 只支持单继承,不支持多继承,但支持多层继承。
多层继承:子类 A 继承父类 B,父类 B 可以继承父类 C。
package com.qdu.test3;
public class A {
public void methodA(){
System.out.println("AAA..类中的method方法");
}
}
package com.qdu.test3;
public class B extends A {
public void methodB(){
System.out.println("BBB...类中的method方法");
}
}
package com.qdu.test3;
public class C extends B{
}
package com.qdu.test3;
public class TestExtends {
public static void main(String[] args) {
C c = new C();
c.methodA(); // 输出:AAA..类中的method方法
c.methodB(); // 输出:BBB...类中的method方法
}
}
3.2 继承中成员变量的访问特点
在子类方法中访问一个变量:先在子类局部范围内找,然后在子类成员范围内找,最后在父类成员范围内找。
注意:如果子父类中出现了重名的成员变量,通过就近原则会优先使用子类的。如果一定要使用父类的,可以通过 super 关键字进行区分。
super 关键字的用法和 this 关键字的用法相似:
- this:代表本类对象的引用
- super:代表父类存储空间的标识(可以理解为父类对象的引用)
![在这里插入图片描述](https://img-blog.csdnimg.cn/84e3ced919594d0883def21d43f3945a.png#pic_center)
public class Fu {
int a = 10;
}
public class Zi extends Fu {
public void method(){
System.out.println(a); // 10
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
public class Fu {
int a = 10;
}
public class Zi extends Fu {
// 子父类中出现了重名的成员变量
int a = 20;
public void method(){
System.out.println(a); // 20
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
public class Fu {
int a = 10;
}
public class Zi extends Fu {
int a = 20;
public void method(){
int a = 30;
System.out.println(a); // 30
System.out.println(this.a); // 20
System.out.println(super.a); // 10
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
3.3 继承中成员方法的访问特点
通过子类对象访问一个方法:先在子类成员范围内找,然后在父类成员范围内找。
public class Fu {
public void show() {
System.out.println("父类show方法");
}
}
public class Zi extends Fu {
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); // 父类show方法
}
}
public class Fu {
public void show() {
System.out.println("父类show方法");
}
}
public class Zi extends Fu {
public void show() {
System.out.println("子类show方法");
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); // 子类show方法
}
}
public class Fu {
public void show() {
System.out.println("父类show方法");
}
}
public class Zi extends Fu {
public void show() {
System.out.println("子类show方法");
}
public void method() {
show(); // 子类show方法
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
public class Fu {
public void show() {
System.out.println("父类show方法");
}
}
public class Zi extends Fu {
public void show() {
System.out.println("子类show方法");
}
public void method() {
this.show(); // 子类show方法
super.show(); // 父类show方法
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
3.4 方法重写
方法重写:在继承体系中,子类出现了和父类一模一样的方法声明(方法名、参数列表、返回值类型)。
方法重载:在同一个类中,方法名相同,参数列表不同,与返回值无关。
方法重写的应用场景:当子类需要父类的功能,而功能主体子类有自己特有内容,可以重写父类中的方法,这样既沿袭了父类的功能,又定义了子类特有的内容。
package com.qdu.override;
public class iPearV1 {
public void call(String name) {
System.out.println("给" + name + "打电话");
}
public void smallBlack() {
System.out.println("speak english...");
}
}
package com.qdu.override;
public class iPearV2 extends iPearV1 {
public void smallBlack() {
super.smallBlack();
System.out.println("说中文");
}
}
package com.qdu.override;
public class TestOverride {
public static void main(String[] args) {
iPearV2 i = new iPearV2();
i.smallBlack();
}
}
(1) 父类中私有方法不能被重写。
(2) 父类中静态方法不能被重写。如果子类中也存在一个方法声明一模一样的方法,可以理解为,子类将父类中同名的方法隐藏了起来,并非是方法重写!
结论:父类静态方法,子类必须通过静态方法进行重写;父类非静态方法,子类也必须通过非静态方法进行重写。
public class Fu {
public static void show() {
System.out.println("Fu...");
}
}
public class Zi extends Fu {
// @Override
// 注解:检查当前的方法是否是一个正确的重写方法
public static void show() {
System.out.println("Zi...");
}
}
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); // Zi...
}
}
(3) 子类重写父类方法时,访问权限必须大于等于父类。
![在这里插入图片描述](https://img-blog.csdnimg.cn/08100ab9b01045a29e840ad61647175f.png#pic_center)
3.5 继承中构造方法的访问特点
子类中所有的构造方法默认都会访问父类中无参的构造方法,这是因为子类在初始化的时候,有可能会使用到父类中的数据。如果父类没有完成初始化,子类将无法使用父类的数据。因此,子类初始化之前,一定要先完成父类初始化。
系统在每一个构造方法中,默认隐藏一句代码 super();
。
注意:如果我们编写的类没有手动指定父类,系统也会自动继承 Object(Java 继承体系中的最顶层父类)。
package com.qdu.constructor;
public class Person {
private String name;
private int age;
public Person() {
super();
System.out.println("我是父类的空参数构造方法");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("我是父类的带参数构造方法");
}
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;
}
}
package com.qdu.constructor;
public class Student extends Person {
// 子类特有的属性
private int score;
public Student() {
System.out.println("我是子类的空参数构造方法...");
}
public Student(int score) {
this.score = score;
System.out.println("我是子类的带参数构造方法!!!");
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
package com.qdu.constructor;
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
// 我是父类的空参数构造方法
// 我是子类的空参数构造方法...
Student stu2 = new Student(100);
// 我是父类的空参数构造方法
// 我是子类的带参数构造方法!!!
}
}
如果父类中没有空参构造方法,只有带参构造方法,如何解决?
(1) 子类通过 super 手动调用父类的带参构造方法。
package com.qdu.constructor;
public class Test2 {
public static void main(String[] args) {
}
}
class Fu {
int age;
// 带参数构造方法
public Fu(int age) {
this.age = age;
}
}
class Zi extends Fu {
public Zi(int age){
super(age);
}
}
(2) 子类通过 this 去调用本类的其他构造方法,本类其他构造方法再通过 super 去手动调用父类的带参的构造方法。
注意:this(…)、super(…) 都必须放在构造方法的第一行有效语句,所以二者不能共存。
package com.qdu.constructor;
public class Test2 {
public static void main(String[] args) {
}
}
class Fu {
int age;
// 带参数构造方法
public Fu(int age){
this.age = age;
}
}
class Zi extends Fu {
public Zi() {
// super(); 此时不存在
this(10);
}
public Zi(int age){
super(age);
}
}
内存图解:
package com.qdu.constructor;
public class Person extends Object {
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;
}
}
package com.qdu.constructor;
public class Student extends Person {
// 子类特有的属性
private int score;
public Student() {
super();
}
public Student(String name, int age, int score) {
super(name, age);
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
package com.qdu.constructor;
public class Test {
public static void main(String[] args) {
Student stu = new Student("张三", 23, 100);
System.out.println(stu.getName() + "..." + stu.getAge() + "..." + stu.getScore());
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/168417f3921b4b3d80019aae01469195.png#pic_center)
4.抽象类
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法。
抽象方法的定义格式:public abstract 返回值类型 方法名(参数列表);
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
抽象类的定义格式:public abstract class 类名 {}
注意:
- 抽象类不能实例化,即不能创建对象。
- 抽象类中有构造方法。
- 抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类的子类,要么重写抽象类中的所有抽象方法,要么将自己也变成一个抽象类。
package com.qdu.test1;
public abstract class Animal {
public void drink() {
System.out.println("喝水");
}
public abstract void eat();
}
package com.qdu.test1;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
package com.qdu.test1;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
package com.qdu.test1;
public class Test1Animal {
public static void main(String[] args) {
Dog d = new Dog();
d.eat(); // 狗吃肉
d.drink(); // 喝水
Cat c = new Cat();
c.drink(); // 喝水
c.eat(); // 猫吃鱼
}
}
5.模板设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码的可靠性和程序的重用性。
模板设计模式:把抽象类整体看做成一个模板,模板中不能决定的东西定义成抽象方法,让使用模板的类(即继承抽象类的类)去重写抽象方法实现需求。
模板设计模式的优势:模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可。
package com.qdu.test2;
public abstract class CompositionTemplate {
public void write() {
System.out.println("<<我的爸爸>>");
body();
System.out.println("啊~,这就是我的爸爸");
}
public abstract void body();
}
package com.qdu.test2;
public class Tom extends CompositionTemplate {
@Override
public void body() {
System.out.println("那是一个秋天,风儿那么缠绵," + "那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中,爸爸蹬不动,他就站起来蹬...");
}
}
package com.qdu.test2;
public class Test {
public static void main(String[] args) {
Tom t = new Tom();
t.write();
}
}
6.final 关键字
final 关键字是最终的意思,可以修饰方法、变量、类。
- 修饰方法:表明该方法是最终方法,不能被重写。
- 修饰变量:表明该变量是常量,不能再次被赋值。
- 修饰类:表明该类是最终类,不能被继承。
常量的命名规范:如果是一个单词,所有字母大写;如果是多个单词,所有字母大写,但是中间需要使用 _
分隔。
final 修饰基本数据类型变量:数据值不能发生改变。
final 修饰引用数据类型变量:地址值不能发生改变,但是地址里面的内容是可以发生改变的。
final 修饰成员变量,要么在创建的时候直接给值,要么在构造方法结束之前完成赋值。
7.代码块
在 Java 中,使用 { }
括起来的代码被称为代码块。
7.1 局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率
package com.qdu.block.local;
public class Test {
public static void main(String[] args) {
{
int a = 10;
System.out.println(a);
}
// System.out.println(a);
}
}
7.2 构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时候,都会执行该代码块中的代码,并且在构造方法执行前执行
作用:将多个构造方法中相同的代码抽取到构造代码块中,提高代码的复用性
package com.qdu.block.construction;
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student(10);
}
}
class Student {
{
System.out.println("好好学习");
}
public Student() {
System.out.println("空参数构造方法");
}
public Student(int a) {
System.out.println("带参数构造方法......");
}
}
7.3 静态代码块
位置:类中方法外定义
特点:需要通过 static 关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作
package com.qdu.block.mstatic;
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person(10);
}
}
class Person {
static {
System.out.println("我是静态代码块, 我执行了");
}
public Person(){
System.out.println("我是Person类的空参数构造方法");
}
public Person(int a){
System.out.println("我是Person类的带参数构造方法...");
}
}