目录
1.static 静态关键字
1.1 加载时间
标有静态关键字的属性或方法,会在类加载时加载,所以静态标识符修饰的方法不可调用普通方法或普通成员,因为他们还没被实例化(没被new)
1.2 类变量、静态变量
- 在类内部创建实例对象 ,添加关键字static的对象(变量)为类变量,或静态变量
- 没加static修饰的变量称为实例变量,普通变量,非静态变量
class Tool{ //静态变量,类变量 static int counts = 100; //普通变量,实例变量,非静态变量 int count ; }
1.2.1 类变量的作用
1.静态对象会被所有该类的对象实例共享
class test3{ public static void main(String[] args) { Tool tool1 = new Tool(); Tool tool2 = new Tool(); System.out.println(tool2.counts); //100 System.out.println(tool1.counts); //100 //改变一个 对象的静态变量的值,另一个也会跟着改变 tool2.counts = 150; System.out.println(tool2.counts); //150 System.out.println(tool1.counts); //150 } }
2.静态方法和普通方法都可以访问本类的静态成员
//静态方法 public static int getCounts(){ return counts; } // 普通方法 public int getC(){ return counts; }
3.静态属性初始化:在类中:访问修饰符 static 属性 变量= 方法 或 数
static int counts = 100;
1.2.2 类变量的细节
- 使用static:当我们需要让某个类共享一个变量就需要此修饰符(区别:共享和独享)
- 类变量,静态变量为加static的变量,实例变量,普通变量,非静态变量为不加static的变量
- 普通变量不能通过 类.变量 来访问,但静态变量可以使用 类.静态方法(本例中为 Tool.counts)
- 在类中静态方法初始化时不能将普通变量赋给静态变量(因为普通变量还未加载)
1.3 类方法
static 修饰的成员的方法,在访问修饰符允许的情况下,在类外可以通过类名.类方法直接调用(一般充当工具)
//在Tool类中定义 public static int getCounts(){ return counts; } //类外调用格式 Tool.getCounts();
![]()
在Math库中的数学函数 sin为例
1.3.1 类方法细节
- 类方法无this的参数
- 可以通过类名也可以通过对象名调用(需注意访问权限)
- 类方法中不允许 this 和 super,普通方法可以使用this和super(因为静态成员在类实例化之前加载)
- 静态方法只能访问静态成员和静态方法,普通的不可以被访问,但普通成员方法可以访问非静态和静态成员(因为静态成员在类实例化之前加载)
2. { }代码块
- 代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通{ }包围起来。
- 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
好处:相当于是另外一种形式的构造器(补充),可以做初始化的操作。如果多个构造器都有重复语句,可以抽取到代码块中。
2.1 普通代码块 {}
- 在创建对象时就会执行,没有次数限制
- 只使用类的静态成员就不会隐式调用代码块!
@SuppressWarnings("all")
class Tool{
{ System.out.println("父类普通代码块被调用");}
//static{System.out.println("父类静态代码块被调用");}
static int counts = 100;
int count ;
Tool(){
//System.out.println("父类构造器被调用");
}
//静态方法
public static int getCounts(){
return counts;
}
// 普通方法
public int getC(){
return counts;
}
}
class test3{
public static void main(String[] args) {
Tool tool1 = new Tool();
Tool tool2 = new Tool();
Tool tool3 = new Tool();
Tool tool4 = new Tool();
Tool tool5 = new Tool();
Tool tool6 = new Tool();
System.out.println(Tool.counts);
}
}
2.2静态代码块 static{}
- static代码块,作用为初始化,在类加载时执行,并且只执行一次。优先级高于方法
- 实用类的静态成员也会触发静态代码块
@SuppressWarnings("all")
class Tool{
//{ System.out.println("父类普通代码块被调用");}
static{System.out.println("父类静态代码块被调用");}
static int counts = 100;
int count ;
Tool(){
//System.out.println("父类构造器被调用");
}
//静态方法
public static int getCounts(){
return counts;
}
// 普通方法
public int getC(){
return counts;
}
}
class test3{
public static void main(String[] args) {
//仍然会触发代码块
System.out.println(Tool.getCounts());
//添加分割线,这样就可以判断是哪条语句触发了静态代码块执行
System.out.println("===============");
Tool tool1 = new Tool();
// Tool tool2 = new Tool();
/* Tool tool3 = new Tool();
Tool tool4 = new Tool();
Tool tool5 = new Tool();
Tool tool6 = new Tool();
System.out.println(Tool.counts);*/
}
}
![6cee15afde684754af4fd38ee7087ad6.png](https://i-blog.csdnimg.cn/blog_migrate/366d30d3aeb9dcdc49e358aaabafca7e.png)
可见是第一条使用静态方法的语句执行了静态代码块
2.3继承关系中代码块和构造器加载顺序
在继承关系中 生成子类的对象 代码块和构造器生成的顺序为:
- 父类的静态代码块和静态属性先执行
- 子类的静态
- 父类的普通
- 父类的构造
- 子类的普通
- 子类的构造
先设计好父类和子类
//父类
@SuppressWarnings("all")
class Tool{
// 代码块
{ System.out.println("父类普通代码块被调用");}
static{System.out.println("父类静态代码块被调用");}
//属性
static int counts = 100;
int count ;
//构造器
Tool(){
System.out.println("父类构造器被调用");
}
//静态方法
public static int getCounts(){
return counts;
}
// 普通方法
public int getC(){
return counts;
}
}
//子类
@SuppressWarnings("all")
class Tool2 extends Tool{
//代码块
static{System.out.println("子类静态代码块被调用");}
{System.out.println("子类普通代码块被调用");}
//构造器
Tool2(){
System.out.println("子类构造器被调用");
}
}
//运行
class test3{
public static void main(String[] args) {
Tool2 tool2 = new Tool2();
}
}
![76ad45a64b1c496196911d7ea9c6c813.png](https://i-blog.csdnimg.cn/blog_migrate/7ff578eaeece77b4d3810d0016cb1409.png)
运行结果
1.类加载的时候:
- new时
- 创建子类对象时父类也会被加载,父类先被加载
- 使用类静态成员时(静态属性,方法)
2.调用等级
- 静态
- 普通
- 构造器
3.构造器的最前面隐含了super() 和 调用普通代码块,静态相关的代码属性初始化,在类加载时就执行完毕,因此是优先于构造器和普通代码快执行的
- 即运行构造器(但不先执行方法体中的命令):
- super()隐式加载父类构造器,同时满足此规则
- 普通代码块
- 剩下的部分(构造器部分)
4.创建一个子类对象,静态代码块,普通代码块,静态属性初始化,普通属性初始化,执行顺序如下(静态优先级最高(父,子),然后父类,子类)
3. final 关键字
- 不希望类被继承
- 不希望方法被重写
- 不希望属性被修改
- 不希望值被修改
- 不希望某个局部变量被修改
3.1 final关键字细节
- 被修饰的一般被称为常量,一般命名为大写字母
- 定义必须初始化赋值,之后将不能修改,可以直接赋值,也可以在代码块赋值,也可以在构造器赋值
![]()
![]()
普通变量初始化,普通代码块赋值(不能是静态),构造器中赋值
- 如果修饰的是静态属性,那么初始化只能在: 定义时 或 静态代码块
- final类不能被继承,但可以实例化(创建对象,例如String)
- final方法,不能被重写,但类可以被继承
- 一般来说一个final类没有必要再修饰final方法
- final不能修饰构造器
- final修饰static效率更高,不会导致类加载
- 包装类是final类(Integer,Character,Byte,Boolean,Float,Double,Short,Long)
- final修饰基本数据类型变量时代表的是变量的值不能修改,修饰引用数据类型对象(数组,类等)时,对象的值是可以修改的!但不可以直接接受另一个该类的对象的赋值!(见3.2,3.3)
class Fa{ final static int PAR ; static{ PAR = 10; } final int PAR2 /*= 10*/; /* { initpar2 = 10; }*/ Fa(){ PAR2 = 10 ; } final void method(){ } }
3.2 final 修饰基本数据类型
final修饰基本数据类型变量时代表的是变量的值不能修改
3.3 final 修饰引用数据类型
修饰引用数据类型对象(数组,类等)时,对象的值是可以修改的!但不可以直接接受另一个该类的对象的赋值
4. interface 接口
4.1 抽象方法,抽象类
当父类某方法需要声明,但不知道如何实现,可以将其声明为抽象方法(没有方法体!),该类必须也声明为抽象类!
- 抽象类不能被实例化!
- 抽象类不一定包含抽象方法,还可以有实现的方法,一旦有抽象方法,必须声明为抽象类
- 只能修饰 类 和 方法 !
- 抽象类可以有任意的成员
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法(加了大括号就算实现),除非它自己也声明为抽象类
- 抽象方法不能使用private,final,static修饰,因为这些关键字与重写相违背
abstract class abclass{
abstract void method();
}
4.2 接口
关键词 interface
修饰符 interface 接口名
{
- 属性
- 方法(抽象方法,默认方法(default),静态方法)jdk8以后可以使用后两种
}
@SuppressWarnings("all")
interface usb{
//属性只能用public static final修饰
public static final int ccc =1;
//方法只能有抽象方法(abstract可省略)
public abstract void charge();
public void DataTrans();
//默认方法 和 静态方法必须要实现该方法
public default void method2(){};
public static void method3(){};
}
4.3 接口实现
(定义类实现接口)
修饰符类 implements 接口名{
自己属性
自己方法,抽象方法实现
}
@SuppressWarnings("all")
//接口实现
class phone implements usb{
//实现抽象方法必须要添加public
public void charge(){System.out.println("p charge" );}
public void DataTrans(){System.out.println("p DataTrans" );}
//phone 类特有方法
public void playPhonegame(){System.out.println("playPhonegame" );};
}
//接口实现
class computer implements usb{
//实现抽象方法必须要添加public
public void charge(){System.out.println("computer charge" );}
public void DataTrans(){System.out.println("computer DataTrans" );}
//computer类特有方法
public void playComputergame(){System.out.println("playComputergame" );};
}
4.4 调用接口
class workenvironment{
public static void main(String[] args) {
//1.接口类型的变量 可以指向实现了接口的类的对象实例
usb phone = new phone();
phone = new computer();
work(phone);
}
// 形参为接口的方法
static void work(usb u){
u.charge();
u.DataTrans();
}
}
4.5 接口细节
不能被实例化,但可以编译类型为接口,运行类型为实现接口类(向上转型)
![]()
右边为实例化,左边为变量(代表指向)!
接口中所有的方法是public方法。(实现时要写public)
一个普通类实现接口就必须实现接口的所有抽象方法(alt+enter 自动生成重写方法)
用抽象类去实现接口,可以不用实现接口的抽象方法
一个类可以同时实现多个接口(implements 多个接口用逗号分隔)
接口中的属性只能是final的,并且是public static final修饰符, 访问形式是接口名.属性名
一个接口不能继承类,但是可以继承多个接口(extends多个接口逗号分隔)
接口的修饰符只能是public和默认(不写),和类是一样的
4.5 继承和接口的关系
- 接口和继承解决的问题不同
- 继承的价值主要在于:解决代码的复用性和可维护性。
- 接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。即更加的灵活..
- 接口比继承更加灵活
- 接口一定程度上使代码解耦
4.6 接口多态特性
4.6.1 接口引用多态
接口的引用类可以指向该接口的实现类对象实例
4.6.2 接口多态数组
//接口实现
class computer implements usb{
//实现抽象方法必须要添加public
public void charge(){System.out.println("computer charge" );}
public void DataTrans(){System.out.println("computer DataTrans" );}
public void playComputergame(){System.out.println("playComputergame" );};
}
class workenvironment{
public static void main(String[] args) {
//1.接口类型的变量 可以指向实现了接口的类的对象实例
/* usb phone = new phone();
work(phone);*/
/* p charge
p DataTrans*/
//代表创建2个接口变量;
usb[] u = new usb[3];
//向上转型
u[0] = new phone();
u[1] = new phone();
//可以多次改变指向
u[1] = new computer();
//向下转型访问特有方法
for(int i = 0;i < u.length;i++){
if(u[i] instanceof phone){
((phone)u[i]).playPhonegame();
}
else if(u[i] instanceof computer){
((computer)u[i]).playComputergame();
}
else{
//u[2]空指针
}
}
/* playPhonegame
playComputergame*/
}
/* static void work(usb u){
u.charge();
u.DataTrans();
}*/
}