文章目录
Java进阶(第一期)
一、static 关键字
-
static 关键字:修饰符,可以修饰成员变量和成员方法
-
特点:
1. 被类的所有对象所共享
2. 多了一种调用方式,可以通过类名直接调用(推荐使用类名调用) 3. 随着类的加载而加载,优先于对象存在
1.1 被类的所有对象共享
- 如下我用静态修饰符修饰了school成员变量
package com.liujintao.mystatic;
class Student {
String name;
int age;
static String school;
}
- 测试类中代码看我第二个引用,我并没有赋值school,但是我依旧可以打印(这就是共享)
package com.liujintao.mystatic;
/*
static 关键字:修饰符,可以修饰成员变量和成员方法
特点:
1. 被类的所有对象所共享
2. 多了一种调用方式,可以通过类名直接调用(推荐使用类名调用)
3. 随着类的加载而加载,优先于对象存在
*/
public class StaticDemo1 {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
stu1.school = "人工智能竞赛";
System.out.println(stu1.name + "---" + stu1.age + "---" + stu1.school);
System.out.println("---------------------------");
Student stu2 = new Student();
stu2.name = "李四";
stu2.age = 24;
System.out.println(stu2.name + "---" + stu2.age + "---" + stu2.school);
}
}
张三—23—人工智能竞赛
李四—24—人工智能竞赛
就因为school被static修饰,所以,它依旧能够被共享使用
Student stu3= new Student();
System.out.println(stu3.name + "---" + stu3.age + "---" + stu3.school);
null—0—人工智能竞赛
- 这里创建了对象,不赋值,但是我对school进行了static修饰,他能共享到类中所有对象的数据。而前面两个没有被修饰,则打印默认值。
1.2、可以直接使用类名调用(推荐使用)
System.out.println(Student.school);
人工智能竞赛
- 可以直接使用类名调用
1.3 优先于对象的存在
System.out.println(Student.school);
Student stu1 = new Student();
- 这句代码方法放在构造器上面都可以访问到类中的成员变量。
null
因为没有初始值,所以这里结果为默认值。
1.4 static静态内存图
- 类中的静态成员,随着类被加载而加载。对象没有被创建,我们的静态成员已经存在了。
只要类被字节码加载!static静态 修饰的成员就会在 堆空间创建一个 类静态成员变量区。专门存放静态方法数据。
1.5 应用场景
- 成员变量:希望数据被共享的时候,则加上static修饰符
- 成员方法:常用于工具类
二、工具类
2.1 关于静态方法的使用
1. 成员方法什么时候加入 static
- 常用于制作工具类
2. 工具类: 不是描述的事物的,而是帮我们完成一些事情(打工)
3. 如果发现一个类中,所有的方法,全是 static 所修饰
- 那么我们就要手动的修饰类的 构造方法
- 目的:为了不让其他类,在创建对象
创建一个工具类:
package com.liujintao.tools;
public class ArrayTools {
// 将构造方法私有化(因为可以通过类名访问我里面的方法了,不需要再开辟空间了)
private ArrayTools(){};
/**
* 求数组最大值方法
*/
public static int getMax (int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
/**
* 求数组最小值方法
*/
public static int getMin (int[] arr) {
int min = arr[0];
for (int i = 0; i < arr.length; i++) {
if (min > arr[i]) {
min = arr[i];
}
}
return min;
}
/**
* 遍历数组方法
*/
public static void forInput (int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length - 1; i++) {
System.out.print(arr[i] + ",");
}
System.out.print(arr[arr.length - 1] + "]");
}
}
测试使用工具类方法
package com.liujintao.tools;
public class Test {
public static void main(String[] args) {
int[] arr = {11, 22, 33};
// 静态方法直接还用类名访问调用里面的方法(不需要构造器创建对象了)
System.out.println(ArrayTools.getMax(arr));
System.out.println(ArrayTools.getMin(arr));
ArrayTools.forInput(arr);
}
}
输出结果:
33
11
[11,22,33]
问:
为什么这里不需要创建实例对象呢?
答:
static修饰的成员方法,变成了静态类(可以直接访问里面的方法了),没必要在使用构造器创建对象再操作了。记得将工具类里面的构造方法私有化,避免产生浪费。
2.2、关于静态 static 注意事项:
- static 方法中,只能访问静态成员(直接访问)
- static中不允许使用 this 关键字
package com.liujintao.mystatic;
/*
演示静态静态类在不通过实例的时候,我们只能访问到静态的成员变量和方法
*/
public class StaticDemo2 {
static String name= "张三";
static int age = 18;
char gender = '男';
private StaticDemo2(){}; // 将构造方法私有化
/**
* 创建一个静态方法
*/
public static void Method1 () {
System.out.println("我是静态方法");
}
/**
* 创建一个非静态的成员方法
*/
public void Method2 () {
System.out.println("我是一个非静态的成员方法");
}
// 静态的主方法
public static void main(String[] args) {
// 1. 不使用构造器构造实例(直接访问)
System.out.println(name);
System.out.println(age);
Method1();
// 2. 访问非静态的成员(报错),因为类都没被加载使用
// System.out.println(gender); 报错(因为非静态的,需要构造对象使用)
// Method2(); 报错
/**
* 解决方案
*/
StaticDemo2 sd = new StaticDemo2();
System.out.println(sd.gender);
sd.Method2();
}
}
- this不能使用,是因为对象都没被类创建出来,你告诉我this怎么使用呢?所以不能使用。
三、继承 (extends)
- 继承:让类与类之间产生关系(子父类关系),子类可以直接使用
父类中非私有的成员
。
3.1 继承的格式
继承的格式:
- 格式:
public class 子类名 extends 父类名{}
- 示范:
public class zi extends fu {}
- fu: 是父类,也被叫为 基类、超集
- zi: 是子类,派生类
创建类的细节:
- 一个.java文件中可以编写多个class
- 保证类与类之间是平级关系
- 只能有个被public修饰
package com.liujintao.mextends;
public class ExtendsDemo1 {
public static void main(String[] LiuJinTao) {
// 子类访问非私有化的父类成员
Zi1 z1 = new Zi1();
System.out.println(z1.name = "张三");
System.out.println(z1.age = 23);
System.out.println(z1.gender = '男');
// 子类访问父类私有化的成员方法 (get 和 set)
Zi2 z2 = new Zi2();
z2.setScore(99);
z2.setPrice(999.99);
System.out.println(z2.getScore() + "---" + z2.getPrice());
}
}
// 父类
class Fu {
String name;
int age;
char gender;
private double score;
private double price;
// 通过JavaBean中的get和set方法实现子类访问父类私有化的成员
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
// 子类继承父类 Fu
class Zi1 extends Fu {
}
// 子类继承父类 Fu
class Zi2 extends Fu {
}
输出示例:
张三
23
男
99.0---999.99
3.2 什么时候使用继承呢?
- 当类与类之间,存在共同(共性) 的内容的时候,并且生产了相互合理的(如同经理和程序员)都属于员工,此时员工可以设为父类。。从而实现代码的优化
项目经理: 姓名 、 工号、工资
程序员: 姓名、 工号、 工资
- 他们两个之间都存在共性,因此我们可以抽取出,放在父类中,让他俩继承父类。
四、继承 - 成员变量 (访问特点)
4.1 继承中的成员变量出现了重名,如何处理数据呢
如果字符类中出现了重名的成员变量,使用的时候依旧是根据就近原则。
- 那么我想使用父类中重名的成员变量该怎么解决呢?
package com.liujintao.mextends;
import java.sql.SQLOutput;
public class ExtendsDemo2 {
public static void main(String[] args) {
ZiClass zi = new ZiClass();
zi.method();
}
}
class FuClass {
int num = 10;
}
class ZiClass extends FuClass {
int num = 20;
public void method () {
System.out.println(num); // 就近原则 : 20
System.out.println(super.num); // 访问父类 : 10
}
}
- 上面使用了 super 访问了父类的成员变量,如同 this 能够访问本类的所有成员。
4.2 访问成员变量的时候 this 和 super的使用
- this:调用本类成员
- super:调用父类成员
class FuClass {
int num = 10;
}
class ZiClass extends FuClass {
int num = 20;
public void method () {
int num = 30;
System.out.println(num); // 就近原则 : 30
System.out.println(super.num); // 访问父类 : 10
System.out.println(this.num); // 调用本类成员:20
}
}
上面代码就实现了使用不同的关键字访问了不同类作用域中的成员变量。
4.3 如果继承中出现了相同的成员方法,如何处理呢
字父类中,出现了方法声明一模一样的方法(方法名、参数、返回值)
- 在创建子列对象,调用方法的时候,会优先使用子类的方法逻辑
- 很像就近原则,但其实是子类的方法,对父类的方法, 进行了重写操作
public Text {
Zi z = new Zi();
z.show() // 我是子类方法
}
// 父类
class Fu {
public void show() {
System.out.println("我是父类方法");
}
}
// 子类
class Zi {
public void show () {
System.out.println("我是子类方法");
}
}
- 上面代码就是,子类继承了父类,同时自己又添加了成员方法,然后访问到的最终还是子类的方法,这不是就近原则,而是方法重写(下面会详细讲解方法重写)
五、方法重写
5.1 方法重写和方法重载
方法重载(Overload):在同一个类中,方法名相同,参数不同,与返回值无关 → 参数不同:类型不同,个数不同,顺序不同
方法重写(Override):在子父类中,出现了方法声明一模一样的方法(方法名,参数,返回值)相同的。
- 识别是不是方法重写 直接在方法上面使用@ Override 不报错则证明是方法重写,否则不是
- 使用场景:当子类需要父类的方法,但觉得父类方法里面的东西太少了,我想添加或者修改,那么此时我就可以使用方法重写。
5.2 代码示例
package com.liujintao.mextends;
public class ExtendesDemo3 {
public static void main(String[] LiuJinTao) {
Son s = new Son();
s.classHandle();
}
}
class Fathod {
public void classHandle() {
System.out.println("起床");
System.out.println("吃饭");
System.out.println("睡觉");
}
}
class Son extends Fathod {
@Override
public void classHandle() {
// 使用super关键字指定父类的方法,如果我们重写这个方法不需要(可以删除)
super.classHandle();
// 下面我们就可以重写方法(这里添加逻辑)
System.out.println("我是方法重写");
System.out.println("但是我保留了父类方法中的逻辑");
}
}
- 子类使用父类的方法的时候,进行了重写。同时他保留了父类的逻辑。
输出示例:
起床
吃饭
睡觉
我是方法重写
但是我保留了父类方法中的逻辑
5.3 方法重写的注意事项
- 父类中私有方法不能被重写
- 子类重写父类方法,访问权限必须大于等于父类(小于就报错)
5.4 java中继承的特点
要么继承一个,要么多层继承,不能同时继承多个。
实现多层继承的代码实现:
package com.liujintao.mextends;
public class ExtendxDemo04 {
public static void main(String[] LiuJinTao) {
C c = new C();
c.methodC(); // 调用本类方法
c.methodB(); // 调用继承的父级类方法
c.methodA(); // 调用父级继承的爷爷类方法
}
}
class A {
public void methodA () {
System.out.println("我是爷爷辈");
}
}
class B extends A {
public void methodB () {
System.out.println("我是父亲辈");
}
}
class C extends B {
public void methodC () {
System.out.println("我是儿子辈");
}
}
- 以上就是层次继承类的写法(注意这里并没有使用方法重写)
输出示例:
我是儿子辈
我是父亲辈
我是爷爷辈
六、继承中的成员访问特点 - 构造方法
6.1 关于继承中的问题解答
问题1: 构造方法能否被继承?
回答2:不能继承构造方法,因为构造方法只能和类重名。
问题2:子类在创建前是否要先初始化父类?
回答2: 是的,因为子类创建的时候,可能需要涉及到父类。
问题3:子类是如何完成父类的初始化的呢?
回答3:子类只需要能访问到父类的构造方法就能实现
问题4:什么方法是用于对象初始化的?
回答4:构造方法
直接下结论:
- 在所有的构造方法中,都默认隐藏了一句话
super();
- 通过这句代码,来访问父类中的空参构造方法。
6.1 super()访问父类构造方法
- 除了Object类,在所有构造方法的第一行代码,都默默有一句super();通过这句代码,访问父类的空参构造方法。
细节:
- Java当中所有的类,都直接或者间接的继承了 Object 类。
package com.liujintao.mextends.construction;
public class constructionDemo {
public static void main (String[] LiuJinTao) {
Zi zi = new Zi();
Zi z2 = new Zi(520);
}
}
class Fu {
public Fu () {
super(); // 指向的是上级,没有继承则为:Object
System.out.println("我是父类空参构造器");
}
public Fu (int num) {
System.out.println("我是父类带参构造器");
}
}
class Zi extends Fu{
public Zi () {
super();
System.out.println("我是子类空参构造器");
}
public Zi (int num) {
super();
System.out.println("我是子类带参构造器");
}
}
- super();方法,是能够访问父级的空参构造的。
输出示例:
我是父类空参构造器
我是子类空参构造器
我是父类空参构造器
我是子类带参构造器
七、继承构造访问使用练习
7.1 习题
创建一个父类
package com.liujintao.test;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
}
创建第一个子类:
package com.liujintao.test;
public class Teachar extends Person {
// 两个构造器
public Teachar () {}
public Teachar (String name, int age) {
super(name, age);
}
public void teach () {
System.out.println("姓名为" + super.getName() + ",年龄为" + super.getAge() + "岁的老师正在讲课");
}
}
创建第二个子类:
package com.liujintao.test;
public class Student extends Person {
private double score;
public Student () {
}
public Student (String name, int age, double score) {
super(name, age);
this.score = score;
}
public void study () {
System.out.println("姓名为" + super.getName() + ",年龄为" + super.getAge() + "岁,成绩为" + score + "分的学生,正在学习");
}
}
测试类操作两个子类:
package com.liujintao.test;
public class Test {
public static void main(String[] LiuJinTao) {
Teachar th = new Teachar("张三", 24);
Student stu = new Student("李四", 18, 99.9);
th.teach();
stu.study();
}
}
输出示例:
姓名为张三,年龄为24岁的老师正在讲课
姓名为李四,年龄为18岁,成绩为99.9分的学生,正在学习
- 重点就是使用了super();方法继承父类构造器实现数据的存储。然后并且使用super操作父类中的成员方法处理数据逻辑。
7.2 内存图
- 堆内存类中都会有一个super区域,专门存放父类的数据。
八、继承综合案例
需求:
代码如下:
测试类代码:
package com.liujintao.test2;
/**
* 我是测试类
*/
public class Test {
public static void main(String[] LiuJinTao) {
Coder code = new Coder("张三", 23, 15000);
Manager mg = new Manager("李四", 24, 18000, 5000);
// 调用两个子类的的方法
code.work();
mg.work();
}
}
父类代码:
package com.liujintao.test2;
import com.liujintao.mextends.A;
/**
* 我是一个员工类
*/
public class Emeployee {
private String name;
private int age;
private int wage;
public Emeployee() {
}
public Emeployee(String name, int age, int wage) {
this.name = name;
this.age = age;
this.wage = wage;
}
/**
* 方法类
*/
public void work () {
System.out.println("姓名为" + name + ",年龄为" + age + ",工资为" + wage + "的程序员正在编写代码");
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
A
/**
* 获取
* @return wage
*/
public int getWage() {
return wage;
}
/**
* 设置
* @param wage
*/
public void setWage(int wage) {
this.wage = wage;
}
}
子类1代码:
package com.liujintao.test2;
/**
* 我是程序员类
*/
public class Coder extends Emeployee {
// 通过构造器获取数据
public Coder (String name, int age, int wage) {
// 通过 super 操作父级的构造器,初始化父级类中的成员变量
super(name, age, wage);
};
}
子类2代码:
package com.liujintao.test2;
/**
* 我是项目经理类
*/
public class Manager extends Emeployee {
// 奖金
private int bonus;
// 该构造方法接受到实例传递过来的数据,然后通过构造器里面的super方法操作父级的构造器,从而实现初始化数据
public Manager (String name, int age, int wage, int bonus) {
super(name, age, wage);
// 多出来的变量我们自己处理就好了
this.bonus = bonus;
}
public void work () {
// 使用方法重写(并且不继承父级该方法的原有属性)
System.out.println("姓名为" + super.getName() + ",年龄为" + super.getAge() + ",工资为" + super.getWage() + "奖金为" + bonus + "的项目经理正在分配任务...");
}
}
输出示例:
姓名为张三,年龄为23,工资为15000的程序员正在编写代码
姓名为李四,年龄为24,工资为18000奖金为5000的项目经理正在分配任务...
九、this 和 super
- this:代表本类对象的引用
- super:代表父类存储空间的标识
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.本类成员变量 | this.本类成员方法(); | this(); this(…);本类构造方法 |
super | super.父类成员变量 | super.父类成员方法 | super(); super(…);父类构造方法 |
注意:this() 和 super() 都在争夺构造方法第一行的位置,所以二者不能共存。
十、final 关键字的介绍
final:关键字(最终)的意思,可以用来修饰(方法、类、变量)
-
final: 修饰的特点:
- 表名该方法是最终方法,不能被重写
- 表明该类是最终类,不能被继承呢
- 表明该变量是常量,不能在次被赋值
-
final 命名规范:
-
一个单词全部大写:max → MAX
-
多个单词全部大写,单词之间使用_隔开:maxValue → MAX_VALUE
final修饰变量的细节补充:
- 变量是基本数据类型:final 修饰指的是基本类型的数据值不能发生改变
- 变量是引用数据类型:final 修饰指的是引用数据类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的
- 成员变量如果被 final修饰,需要在构造方法结束之前完成复制
本期需要掌握的知识点。
Java进阶开始了(更新中…)加油