关键字Static
如果想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(或类属性)。
当实例化对象时会给对象属性开辟空间,但有一些属性要求所有对象都一样,就希望不开辟那个属性的空间,直接让属性指向一个公共的空间。这种属性就用static来声明
用来修饰的结构:属性、方法;代码块、内部类;
static修饰属性
对比静态变量与实例变量:
1.个数
静态变量在内存空间中只有一份,被多个对象共享
实例变量类的每个对象一份
2.内存位置
实例对象:在堆空间的对象实体中
3.加载时机
静态变量:随着类的加载而加载
实例变量:随着对象的创建而加载
调用者:
静态变量:可以被类直接调用,也可以使用对象调用
实例变量:只能使用对象进行调用
消亡时机:
静态变量:随着类的卸载而消亡
实例变量:随着对象的消亡而消亡
内存解析
static修饰方法
可以通过"类.静态方法"直接调用静态方法
静态方法内可以调用用静态的属性或静态的方法,不可以调用非静态结构(如:属性,方法)
开发中,什么时候要将属性或方法声明为静态的
方法内操作的变量是静态变量,建议声明为静态方法
开发中,常常将工具类中的方法,声明为静态方法
单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
实现思路
要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类的内部仍可以产生该类的对象。因为在类的外部无法创建该类的对象,所以必须要提供一个静态方法来获得这个对象。静态方法只能访问类中的静态成员变量所以,指向类内部产生的该类对象的变量也必须定义成静态的。
如何实现
饿汉式
//饿汉式
class Bank{
//类构造器私有化
private Bank(){
}
//内部创建类
private static Bank instance = new Bank();
//获取当前实例
public static Bank getInstance(){
return instance;
}
}
懒汉式
class GirlFriend{
private GirlFriend(){
}
static GirlFriend instance = null;
private static GirlFriend getInstance(){
if(instance == null)
{
instance = new GirlFriend();
}
return instance;
}
}
对比两种模式
饿汉式:立即加载,随着类的加载唯一实例就创建了
懒汉式:延迟加载,需要使用的时候实例才创建
优缺点:
饿汉式:(优点)内存中加载早,线程安全(缺点)内存中占用时间长
懒汉式:(优点)节省内存空间(缺点)线程不安全
应用场景
app是单例的典型应用
应用程序的日志应用
理解main方法的语法
public static void main(){}
理解一:可以看作是一个普通的静态方法
理解二:看做是程序的入口格式是固定的
类的成员之四:代码块
代码块的作用:用来初始化类或对象的信息
代码块的修饰:只能使用static进行修饰
//静态代码块
{
System.out.println("非静态代码块");
}
代码块的分类:
静态代码块:用static进行修饰的
非静态代码块:不用static进行修饰的
具体使用
静态代码块:>随着类的加载而执行 >由于类的加载只会执行一次所以这个静态代码块也只会执行一次 >用来初始化类的信息 >只能调用静态的结构
非静态代码块:>随着对象的创建而执行 >用来初始化对象的信息 >静态非静态结构 都能调用
从类加载开始的执行顺序
静态代码块 --> 普通代码块 --> 构造器
总结:属性赋值过程
1.可以给类的非静态对象赋值的位置有:
>默认初始化 >显式初始化,代码块中初始化 >构造器中初始化 (按顺序的)
>有了对象后通过 对象.属性的方法赋值
final关键字
final 可以用来修饰的结构:类,方法,变量
用法:final修饰类:表示此类不能被继承
final修饰方法:表示此方法不能被重写
final修饰类:不能有子类
final修饰变量:此时的变量其实就变成了常量,一旦赋值就不可更改
final与static搭配:修饰成员变量时,此成员变量称为:全局常量
abstract关键字
被abstract修饰的类不能实例化
被abstract修饰的方法 只有方法的声明没有方法体
包含抽象方法的类,必须是抽象类
继承抽象类的子类必须重写抽象类中的抽象方法
abstract不能与哪些关键字共用?
不能用abstract修饰私有方法,静态方法,final的方法,final的类。
接口
定义接口关键字:interface
接口内部结构的说明:
可以声明:
属性:必须使用public static final修饰
方法:jdk8之前:声明抽象方法,修饰为public abstract
jdk8:声明静态方法,默认方法
public class SubClassTest {
public static void main(String[] args) {
//1 接口中声明的静态方法只能通过接口调用,实现类用不了
CompareA.methodA();
// SubClass.methodA();//会报错
//2 接口中声明的默认方法可以被实现类继承
//3 如果类实现了两个接口,而两个接口中有同名同参数的默认方法。则实现类在没有重写此两个接口相同默认方法的情况下会报错
SubClass s1 = new SubClass();
s1.method2();
//4 子类在没有重写方法的情况下,在继承类,实现接口的情况下,优先实现父类的方法
}
}
public class SubClass extends SuperClass implements CompareA,CompareB{
public void method(){
CompareA.super.method2(); //调用接口默认方法的写法
}
}
jdk9:声明私有方法
接口与类的关系:实现关系
格式:class A extend superA implement B,C{}
A相较于superA来讲叫做子类,
A相较于B,C来讲,叫做实现类。
满足此关系后,说明:
类可以实现多个接口,弥补单继承性的局限性
类必须将实现的接口中的所有抽象方法都重写,方可实例化。或者声明为抽象类
接口与接口的关系:继承关系,而且可以多继承
接口的多态性:接口名 变量名 = new 实现类对象;
面试题:区分抽象类和接口
共性:都可以声明抽象方法,都不能实例化
不同:抽象类一定有构造器。接口没有构造器
类与类之间是继承关系,接口与类之间是实现关系,接口与接口之间是多继承关系
内部类
将一个类A定义在类B中,A就是内部类,B就是外部类
分类
>成员内部类:直接声明在外部类的里面。
>静态类成员
实例创建:静态成员类 new 外部类.内部类()
>非静态成员类
实例创建: 需要先实例化外部类
Person p1 = new Person();
Person.Bird bird = new Bird();
>局部内部类:声明在方法内,构造器内,代码块内部类
成员内部类的理解:
>从类的角度看:
-内部可以声明属性,方法,构造器,代码块,内部类等结构
-可以继承父类,可以实现接口
-可以用final,abstract修饰
>从外部类的成员的角度看:
-可以调用外部类的结构
-各种权限修饰词都能用
-可以使用static修饰
枚举类
枚举类型本质上也是一种类,只不过这个类的对象是有限的,固定的几个,不能让用户随意创建。
本质上就是在类的内部给你造好了不让你自己造
例子:性别:男,女
> 开发中,如果针对某个类,其实例时确定个数的。则推荐将此类声明为枚举类。
> 如果枚举类的实例只有一个,则可以看作是单例的实现方式
使用方法
enum Season1{
//1必须在开头声明实例化对象,对象间用,隔开
SPRING("春","暖"),
SUMMER("夏","热");
//私有变量
private final String SeasonName;
private final String SeasonDesc;
//构造器
private Season1(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
//提供get方法
public String getSeasonName() {
return SeasonName;
}
public String getSeasonDesc() {
return SeasonDesc;
}
}
使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类,不要再显示的定义其父类,否则报错.
枚举类实现接口的操作
enum Season1 implements Saysth{
//1必须在开头声明实例化对象,对象间用,隔开
SPRING("春","暖"){ //让枚举类的每一个对象去重写接口中的抽象方法
@Override
public void say() {
System.out.println("春天啦");
}
},
SUMMER("夏","热"){
@Override
public void say() {
System.out.println("夏天啦");
}
};
//私有变量
private final String SeasonName;
private final String SeasonDesc;
//构造器
private Season1(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
//提供get方法
public String getSeasonName() {
return SeasonName;
}
public String getSeasonDesc() {
return SeasonDesc;
}
//方式一直接重写接口,不同枚举类对象调用此方法,执行的是同一个方法
// @Override
// public void say() {
// System.out.println("1");
// }
}
interface Saysth{
public void say();
}
注解Annotation
包装类
由于有很多只针对对象设计的API,基本数据类型无法穿入,所以有了包装类,目的是把基本数据类型也给传入。
使用方式:
基本数据类型 --> 包装类
//推荐
int i1 = 1;
Integer ii1 = Integer.valueOf(i1);
//不推荐
int i2 = 1;
Integer ii2 = new Integer(i2)
包装类-->基本数据
Integer ii1 = Integer.valueOf(1)
int i1 = ii1.intValue()
jdk5.0新特性:自动装箱,自动拆箱。
int i1 =1;
Integer ii1 = i1 //自动装箱
int i2 = ii1 //自动拆箱
基本数据类型,包装类 ---> String类型:调用String的重载的静态方法valueOf()
int i1 = 10;
String str1 = String.valueOf(i1);
法2
int i2 = 0;
String str2 = i2+""
String类型 --->转换为基本数据类型,包装类:调用包装类的静态方法:parseXxx()
String i1 = "123";
int i1 = Integer.parseInt(s1);
企业真题
静态属性和静态方法是否可以被继承?是否可以被重写?
答:静态方法不能被重写,不存在多态性
是否可以从一个static方法内部发出对非static方法的调用
答:只能通过对象来对非静态方法的调动
被static修饰的成员(类,方法,成员变量)能否再使用private进行修饰?
完全可以,除了代码块