目录
1. static关键字
一个类的成员包括变量、方法、构造方法、代码块和内部类。static 可以修饰除了构造方法以外的所有成员。
使用 static 修饰的成员是静态成员,属于某个类的,一个类只有一份
,不使用 static 修饰的成员为实例成员,属于类的每个对象,被所有的对象共享
1.1 static 变量
- 非静态方法可以访问静态变量、非静态变量
- 静态方法只能访问静态变量
public class Student {
int sno;
String name;
int age;
String cup; // 水杯
// 使用static修饰后,整个类只有这一个
static String waterMachine; // 饮水机
// 默认构造方法
public Student() {
}
// 【【重载】】构造方法
public Student(int sno, String name) {
this.sno = sno; // 1. 调用成员变量
this.name = name;
}
public Student(int sno, String name, int age) {
this(sno, name); // 2. 调用构造方法
}
public void show() {
System.out.println("My name is " + name);
}
public void study() {
this.show(); // 3. 调用成员方法
System.out.println("good good study!");
}
public static void main(String[] args) {
System.out.println(Student.waterMachine); // null
Student stu = new Student();
stu.waterMachine = "海尔饮水机";
System.out.println(Student.waterMachine); // 海尔饮水机
Student stu1 = new Student(2, "李四");
System.out.println(Student.waterMachine);
}
}
static 变量和非 static 变量的区别:
- 份数不同:静态变量 ==》 一个类 1 份, 非静态变量 ==》 一个对象 1 份
- 存储位置不同:静态变量 ==》 方法区 , 非静态变量 ==》 堆内存
- 内存分配空间的时间不同:静态变量 ==》 第一次加载类的时候, 非静态变量 ==》 创建对象的时候
- 生命周期不同:静态变量 ==》 和类的生命周期相同, 非静态变量 ==》 和所属对象相同
- 调用方法不同:静态变量 ==》 通过**类名(推荐)**或对象名调用, 非静态变量 ==》 只能通过对象名调用
1.2 static方法
- 只能访问 static 变量和 static 方法
- 通过类名调用
理解:加载类的时候就加载静态变量和静态方法,此时可能还没有创建对象,所以非静态变量和方法还没有分配空间,无法访问。
private static String name;
public static void show() {
System.out.println(Student.name);
}
1.3 static 代码块
局部代码块 | (成员)代码块 | static代码块 | |
---|---|---|---|
位置 | 方法中 | 类中 | 类中 |
数量 | 多个 | 多个 | 多个 |
执行顺序 | 依次执行 | 依次执行 | 依次执行 |
作用 | 局部代码块中定义的变量作用范围只限于当前代码块 | 每次创建对象的时候都执行;先执行代码块,再执行构造方法;实际开发中很少用,可以将各个构造方法中公共的代码提取到代码块;匿名内部类不能提供构造方法,此时初始化操作U;放到代码块中 | 第一次加载类的时候执行,最先执行,只执行一次。给静态变量赋初始值,一般用于执行一些全局性的初始化操作 (创建工厂、加载数据库初始信息) |
2. package 包和 import 导入
2.1 package关键字
使用包的作用:
- 解决类重名的问题
- 还和访问权限有关系
定义包:
- 域名倒写:com.lwclick.包名
- 通常是类的第一句非注释性语句
Java常用包:
- java.lang:无需导入直接用的类,Java的核心类,如 String、Math、Integer、System、Thread
- java.util:一些实用的工具类,如定义系统特性、使用与日期日历相关的函数
- java.io:包含多种输入/输出功能的类
- java.net:包含与网络相关的操作的类
2.2 import关键字
-
使用其他包的类,需要使用import进行导入,从而可以在本类中直接使用类名进行操作。
-
导入时,可以使用通配符
*
,访问包下所有的类。
(java.util.*
只能访问 util 下所有的类,不能直接访问java.util.concurrent.
下面的类) -
如果想导入两个同名的类,其中一个使用 import 进行导入,另一个使用全限定类名(包名+类名)进行导入
静态导入:
import static
java.lang.Math.*; 导入的不是类或接口,而是静态的方法和静态的属性(JDK1.5之后)
静态导入后,在本类可以直接使用静态的方法或者属性。
3. 文档注释
/**
* 注释文字
*/
养成良好习惯,在类,方法,属性前面加文档注释,然后就可以使用 IDEA 快捷的导出API
步骤:Tools ==》 Generate JavaDoc… ==》 根据需求自己配置参数,在 Other command line arguments 一栏里输入:-encoding utf-8
用来调整编码格式
4. 封装性
面向对象的三大特征之一,例如电视机,我们只需要知道如何使用它暴露的接口(比如电源开关)即可,不需要知道内部的各种细节。
封装追求的就是“高内聚,低耦合”,高内聚是类中的功能关系密切,数据的操作细节由自己完成,不允许外部干涉,低耦合是仅暴露少量的方法给外部使用。
同一个类 | 同一个包中的类 | 子类 | 所有包的所有类 | |
---|---|---|---|---|
private | * | |||
default(默认) | * | * | ||
protected | * | * | *(其他包中该类的子类) | |
public | * | * | * | * |
规范:
- 将类的属性全都设为私有(private)的,然后向外暴露 public 的 getter / setter方法(可以在其中加入逻辑判断)
- 一些只用于本类的辅助性方法可以用 private 修饰,希望其他类调用的方法用 public 修饰
public class Student {
// 使用private封装成员属性
private int sno;
private String name;
public Student() {
}
public Student(int sno, String name) {
// 直接调用本类封装好的方法,复用代码
this.setSno(sno);
this.setName(name);
}
// 暴露给外部public声明的操作属性的方法
public int getSno() {
// 其内可以添加if判断
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() > 4) {
this.name = name.substring(0, 4);
return;
}
this.name = name;
}
}
class TestStu {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("张三张三张三");
System.out.println(stu.getName());
}
}
5. 继承性
面向对象编程的三大特征之一,让我们更加容易实现对于已有类的扩展(子类可以从父类那里继承变量和方法),实现代码的重用。
父类 Animal
public class Animal { // 没有明确写出继承关系,那么就是继承了 Object
private String color;
private int age;
public String testFiled;
public Animal() {
}
public Animal(String color, int age) {
super(); // 不写也是默认存在的,调用 Object类的构造方法
this.color = color;
this.age = age;
}
public void eat() {
System.out.println("-------- eat() ---------");
}
public void sleep() {
System.out.println("-------- sleep() --------");
}
}
子类 Dog
public class Dog extends Animal{
// 父类使用private修饰的成员变量,虽然可以继承,但是不可以直接访问,需要使用 super 关键字
private String nickName; // 昵称,子类自己的成员变量
public Dog() {
}
public Dog(String color, int age, String nickName) {
super(color, age); // 调用父类的构造函数
// super.testFiled; 调用父类 public 或者 protected 修饰的成员变量
// super.sleep(); 调用父类 public 修饰的成员方法
this.nickName = nickName;
}
public void guard() {
System.out.println("Dog guard.....");
}
/**
* 父类的方法无法满足子类的需求
* 【【重写】】父类的方法
*/
@Override
public void eat() {
System.out.println("------ Dog eat() ---------");
}
}
测试类
public class Test {
public static void main(String[] args) {
Dog dog = new Dog("褐色", 3, "旺财");
dog.eat(); // 调用自己重写的 eat 方法
dog.sleep(); // 调用父类的 sleep 方法
}
}
继承使用要点:
- 父类:超类,基类, 子类:派生类
- Java只有单继承
- 子类继承父亲,可以得到父类的全部属性和方法(除了构造方法),但不一定能直接访问
- 如果定义一个类时,没有调用 extends,则它的父类是:java.lang.Object
重写与重载
-
总体的区别:解决的问题不同,即作用不用
- 重载 overload:同一个类中,在一个类里面为一种行为提供多种实现方式并提高可读性
- 重写 override:子类和父类间,父类无法满足子类的要求,子类通过方法重写满足要求
-
细节的区别:
- 重载,只要方法名相同,参数不同即可,与修饰符、返回值、抛出异常都无关
- 重写,要求在方法名相同,参数相同的基础上,
- 修饰符: 子类 >= 父类
- 返回值: 子类 <= 父类
- 抛出的异常:子类 <= 父类
-
扩展:
- 方法使用 final 修饰,无法被重写
- 静态方法无法进行方法重写。父类中有一个的 static 方法,且在子类中有个完全相同的静态方法,那么该子类实际上只是将父类中的同名方法进行了隐藏,而非重写。添加 @Override 注解将会报错
5.1 成员变量的隐藏
如果父类和子类有同名的成员变量,不存在变量的重写,分别占有自己的空间,子类的成员变量优先。
父类 Animal
public class Animal {
protected String color = "Animal color";
private int age;
}
子类 Dog
public class Dog extends Animal{
private String nickName; // 昵称
private String color = "Dog color";
public void getColor() {
System.out.println(color); // 调用的是自己的color ==> Dog color
System.out.println(this.color); // 调用自己的color ==> Dog color
System.out.println(super.color); // 调用父类的color ==> Animal color
String color = "local color";
System.out.println(color); // 调用的是局部变量color ==> local color
}
}
5.2 构造方法的执行顺序
- 在子类的构造方法里,第一句默认是 super(),调用父类无参数的构造方法,所以先执行父类的构造方法
- 在子类的构造方法里,第一条语句也可以显式的指定父类有参数的构造方法 super(…)
- 也可以显式的指定为当前类的构造方法 this(…)
注意事项:
- 每个类最好要提供无参数的构造方法
- 构造方法的第一条语句,可以使用 super 或者 this 调用构造方法
- 构造方法中,不能同时使用 super 和 this