static关键字
- 可以用来修饰属性,方法,代码块,内部类
修饰属性
属性按照是否使用static修饰,又分为:静态属性(类变量) vs 非静态属性(实例变量)
- 非静态变量:创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的其他属性值的修改
- 静态变量:创建了类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的变量
- 静态变量随着类的加载而加载,可以通过
类.静态变量
的方式进行调用 - 静态变量的加载要早于对象的创建
- 由于类只加载一次,静态变量在内存中也只存在一份:存在方法区的静态域中
修饰方法
- 随着类的加载而加载,可以通过
类.静态方法
来调用 - 静态方法中只能调用静态的方法或属性
- 非静态方法中既可以调用非静态结构,也可以调用静态结构
- 在静态的方法内,不能够使用this和super关键字
使用场景
- 属性何时要声明为static
- 属性可以被多个对象所共享的,不会随着对象的不同而不同
- 类中的常量也常常声明为静态的
- 方法何时要声明为static
- 操作静态属性的方法通常设置为静态的
- 工具类中的方法,习惯上声明为静态方法
main()方法的说明
- main()方法是程序的入口
- main()方法也是一个普通的静态方法,可以正常的通过类来调用
- main()方法也可以作为与控制台交互的方式
- 使用idea或eclipse的话,选择 Edit Configurations,编辑带有arguments的项,输入参数,多个参数之间用空格分隔,加不加双引号都可以,再运行就可以使用传入的参数
- 使用控制台的话,先使用javac编译,在运行的时候使用
java class名 参数1 参数2 ......
,参数加不加双引号都可以
代码块
- 作用:用来初始化类、对象
- 结构:
{}
(如果有修饰,只能用static) - 分类:静态代码块 vs 非静态代码块
- 静态代码块:
- 内部可以有输出语句
- 随着类的加载而执行,且只执行一次
- 作用:初始化类的信息
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行要优先于非静态代码块
- 静态代码块内只能调用静态的结构
- 非静态代码块:
- 内部可以有输出语句
- 随着对象的创建而执行
- 每创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内既可以调用静态的结构,也可以调用非静态的结构
属性赋值的先后顺序
final关键字
- final可以修饰类、方法、变量
- final修饰类:此类就不可以被其他类所继承(String、System、StringBuffer)
- final修饰方法:此方法不可以被重写(Object中的getClass()方法)
- final修饰变量:此时的变量就称为是一个常量
- static final可以修饰属性、方法,修饰属性表示该属性是全局常量
- final修饰属性时可以赋值的条件:显式初始化、代码块中赋值、构造器中赋值
- final修饰局部变量:尤其是使用final来修饰形参时,表明此形参是一个常量。当调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,不能重新进行赋值
abstract关键字
- 可以用来修饰类、方法
- 抽象类:
- 此类不能实例化(不能够创建对象)
- 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
- 抽象类中一定有构造器,便于子类对象实例化时调用
- 抽象方法:
- 抽象方法只有方法的声明,没有方法体
- 包含抽象方法的类一定是一个抽象类,但抽象类中可以没有抽象方法
- 子类重写了父类中的所有的抽象方法以后,该子类才可以实例化,否则该子类也要是一个抽象类
- abstract使用注意
- 不能用来修饰属性、构造器等结构
- 不能用来修饰私有方法,静态方法、final的方法、final的类
- 抽象类的匿名子类
// 如果Person是一个抽象类 Person p = new Person() { // 重写抽象方法 };
接口(interface)
接口就是规范,定义的是一组规则。接口的本质是契约,标准,规范。
- Java中,接口和类是并列的两个结构
- 接口的成员:
- JDK7及以前:只能定义全局常量和抽象方法(相关关键字可以省略不写)
- JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法和默认方法
interface Flyable { public static final int MAX_SPEED = 7900; int MIN_SPEED = 1; public abstract void fly(); void stop(); }
- 接口中不能定义构造器,意味着接口不可以实例化
- 开发中,接口都通过让类去实现的方式来使用。如果实现类覆盖了接口中所有的抽象方法,该实现类就可以实例化,否则该实现类仍为一个抽象类(面向接口编程)
- Java类可以实现多个接口,弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE {}
- 接口与接口之间可以继承,而且可以多继承
- 接口的具体使用,提现多态性
- 接口的匿名实现类
Flyable f = new Flyable() { // 覆盖抽象方法 };
JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法和默认方法
public interface CompareA {
// 静态方法
public static void method1() {
System.out.println("CompareA中的静态方法");
}
// 默认方法:public可以省略
public default void method2() {
System.out.println("CompareA中的默认方法");
}
}
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
s.method2();// 默认方法
CompareA.method1();// 静态方法
}
}
class SubClass implements CompareA {
public void method2() {
System.out.println("CompareA中的默认方法的重写");
CompareA.super.method2();// 调用接口中的默认方法
}
}
注意:
- 接口中定义的静态方法只能通过接口来调用
- 接口中定义的默认方法可以通过实现类的对象来调用,如果实现类重写了接口中的默认方法,那么在实现类调用时调用的是重写的方法
- 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的该方法(类优先原则)
- 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,则在实现类没有重写该方法的情况下,会报错(接口冲突),这需要在实现类中重写此方法
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
- 分类:成员内部类(静态、非静态) vs 局部内部类(方法、代码块、构造器)
- 成员内部类和局部内部类在编译后都会生成字节码文件
成员内部类:
- 作为外部类的成员:
- 调用外部类的结构
- 可以用static修饰
- 可以被4种不同的权限修饰
- 作为一个类:
- 类的内部可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承
- 可以被abstract修饰,表示此类不能被实例化
如何实例化成员内部类
public static void main(String[] args) {
// 创建Dog实例(静态成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
// 创建Bird实例(非静态成员内部类)
Person person = new Person();
Person.Bird bird = person.new Bird();
bird.sing();
}
如何在成员内部类中区分调用外部类的结构
public void display(String name) {
// 如果属性名和方法名没有冲突,可以直接调用
System.out.println(name);// 方法的形参
System.out.println(this.name);// 内部类的属性
System.out.println(Person.this.name);// 外部类的属性
}
开发中局部内部类如何使用
// 返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {
// 创建一个实现了Comparable接口的类:局部内部类
class MyComparable implements Comparable {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
return new MyComparable();
}
// 方式二:
public Comparable getComparable() {
return new Comparable() {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
};
}
内部类代码
class Person {
String name;
int age;
public void eat() {
System.out.println("人:吃饭");
}
// 静态成员内部类
static class Dog {
String name;
int age;
public void show() {
System.out.println("卡拉是条狗");
}
}
// 非静态成员内部类
class Bird {
String name;
public Bird() {
super();
}
public void sing() {
System.out.println("我是一只小小鸟");
Person.this.eat();// 调用外部类的非静态的结构
}
}
public Person() {
// 局部内部类
class C {
}
}
{
// 局部内部类
class B {
}
}
public void method() {
// 局部内部类
class A {
}
}
}
在局部内部类的方法中,如果调用局部内部类所声明的方法中的局部变量的话,要求此局部变量声明为final的
public void method() {
int num = 10;// 此时默认为final的;在JDK7之前要求该变量要显式声明为final的
class AA {
public void show() {
System.out.println(num);
}
}
}