文章目录
1、static关键字
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过 new 关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。
我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。
static:静态的
static 可以用来修饰:属性、方法、代码块、内部类。
1.1、static修饰属性
- 被static修饰的属性称为静态变量(类变量)
- 根据是否被static修饰分为:静态变量 VS 非静态变量(实例变量)
- 非静态变量 : 我们创建了类的多个对象,每个对象都独立的拥有了一套类中的非静态属性。 当修改其中一个非静态属性时,不会导致其他对象中同名的属性值的改变。
- 静态变量 :我们创建了类的多个对象,多个对象共享同一个静态变量。当一个对象修改了这个变量,那么其他对象的同名属性值也会随之改变。
- 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。
- 静态变量的加载要早于对象的创建。
- 由于类只会加载一次,则静态变量在内存中也只会存在一次。存在方法区的静态域中
- 可以通过对象调用类变量和实例变量 ,但是通过 类 只能调用 类变量
1.2、类变量 vs 实例变量内存解析
1.3、static修饰方法
- 使用 static 修饰方法称为静态方法
- 随着类的加载而加载,可以通过"类 . 静态方法"的方式调用
- 非静态的方法中,可以调用所有的方法或属性
- 静态方法中,只能调用静态的方法或属性
- 在静态的方法内,不能使用 this 关键字、super 关键字
2、单例设计模式
概述
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为 private,这样,就不能用 new 操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
单例模式的饿汉式
//饿汉式
class Bank{
//私有化构造器
private Bank(){
}
//创建一个static 的对象
private static Bank obj=new Bank();
//提供一个public的方法 获取该对象
public static Bank getInstance(){
return obj;
}
}
单例模式的懒汉式
//私有化构造器
private bank(){
}
//创建一个没有初始化的对象
private static bank obj=null;
//在调用方法时再初始化该对象
public static bank getInstance(){
if(obj == null){
obj = new bank();
}
return obj;
}
单例设计模式的优点
- 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
- 饿汉式与懒汉式的优缺点
- 饿汉式
- 优:线程安全
- 缺:对象加载时间过长
- 懒汉式
- 优:延迟对象创建
- 缺:线程不安全(getInstance()方法添加 synchronize 则线程安全)
- 饿汉式
3、main方法
由于 Java 虚拟机需要调用类的 main()方法,所以该方法的访问权限必须是 public,又因为 Java 虚拟机在执行 main()方法时不必创建对象,所以该方法必须是 static 的,该方法接收一个 String 类型的数组参数,该数组中保存执行 Java 命令时传递给所运行的类的参数。
/*
* main()方法的使用说明
* 1.main()方法作为程序的入口;
* 2.main()方法也是一个普通的静态方法
* 3.main()方法也可以作为我们与控制台交互的方式。
*
*/
public class MainTest {
public static void main(String[] args) { //入口
Main.main(new String[100]);
MainTest test = new MainTest();
test.show();
}
public void show(){
}
}
class Main{
public static void main(String[] args) {
args = new String[100];
for(int i = 0;i < args.length;i++){
args[i] = "args_" + i;
System.out.println(args[i]);
}
}
}
命令行参数用法举例
public class MainDemo {
public static void main(String[] args) {
for(int i = 0;i < args.length;i++){
System.out.println("/*/*/*/"+ args[i]);
}
}
}
4、代码块
- 代码块的作用:用来初始化类、对象的
- 代码块只能被static修饰
- 分类 : 静态代码块 vs 非静态代码块
- 静态代码块
- 内部可以有输出语句
- 随着类的加载而执行,而且只执行一次
- 作用 : 初始化类的信息
- 如果一个类中,定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行,优先于非静态代码块的执行
- 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
- 非静态代码块
- 内部可以有输出语句
- 随着对象的创建而执行
- 每创建一个对象,就执行一次非静态代码块。
- 作用:可以在创建对象时,对对象的属性等进行初始化。
- 如果一个类中,定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法。
代码块的格式
(static){
方法体;
}
5、final关键字
- final:最终的
- final可以用来修饰的结构 : 类、方法、变量
- final修饰一个类:此类不能被其他类所继承。
- final修饰一个方法:此方法不能被子类重写。
- final修饰一个变量,此时“ 变量 ” 变 “常量”
- 修饰属性,可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
- 修饰局部变量 :final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。 一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
- static final 修饰的属性叫做 全局常量
6、抽象类与抽象方法
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
- abstract: 抽象的
- abstract 可以用来修饰的结构:类、方法
- abstract 修饰类 = 抽象类
- 此类不能实例化
- 抽象类中一定有构造器,便于子类实例化时调用
- 开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作
- abstract 修饰方法 = 抽象方法
- 抽象方法,只有方法的声明,没有方法体。
- 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法
- 子类重写父类所以的抽象方法,方可实例化
- 若子类没有重写所以的抽象方法,则子类必须声明为abstract
- abstract 不能用来修饰变量、代码块、构造器;
- abstract 不能用来修饰私有方法、静态方法、final 的方法、final 的类
7、接口
7.1、接口的理解:
- 理解: 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能"的关系。
- 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
- Java中接口与类是两个并列的结构
7.2、接口的定义与规定:
规定
- 接口用 interface 来定义。用 implement 来实现
- 接口中不能定义构造器。意味着接口不可以实例化。
- 接口与接口之间是继承 , 而且可以多继承(多继承机制。)
- Java 类可以实现多个接口
- 弥补了 Java 单继承性的局限性
- 接口通过让类去实现(implements)的方式来使用。 如果实现类覆盖了接口中的所有方法,则此实现类就可以实例化 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
- 接口的主要用途就是被实现类实现。(面向接口编程)
- 接口实际上可以看作一种规范,接口的使用体现了多态性
定义
- 定义接口的成员:只能定义全局常量(public static final)、抽象方法(public abstract)、静态方法、默认方法(JDK8:除了全局常量和抽象方法之外,还可以定义静态方法、默认方法)
- 接口中的所有成员变量都默认是由 public static final 修饰的(默认,可以不写)
- 接口中的所有抽象方法都默认是由 public abstract 修饰的(默认,可以不写)
// 静态方法
public static void staticmethod(){
//方法体;
}
//静态方法只能通过 接口名.staticmethod 来调用
//默认方法
public default void defaultmethod(){
//方法体;
}
//需要通过实现类来调用,但不需要重写
//如果重写了,则调用重写之后的方法
//如果子类中 继承的父类的某个方法 与 实现的接口的默认方法 同名同参 ,那么在子类没有重写的情况下执行父类的方法
//如果实现类只实现了多个接口,而这些接口又定义了 同名同参 的方法 ,则在没有重写的情况下会报错(接口冲突),需要实现类重写
//接口测试
public class InterfaceTest extends fish implements lions,tiger{
@Override
public void eat() {
System.out.println("正在吃东西呢");
}
@Override
public void run() {
System.out.println("它们跑得老快了");
}
public static void main(String[] args){
//调用重写之后的抽象方法
new InterfaceTest().eat();
new InterfaceTest().run();
//调用默认方法 ,在没有重写的情况下 调用父类中的方法,而不是默认方法
// 如果没有继承的话,则需要重写,因为lions,tiger接口都有 同名同参的方法
new InterfaceTest().fight();
//调用静态方法
lions.sleep();
//属性被public static final修饰 多继承情况下只能通过 接口名.属性 调用
System.out.println(lions.name);
//在单继承情况下,则能够通过 接口名.属性 或者 类名.属性 调用
//System.out.println(InterfaceTest.name);
}
}
interface lions{
//全局常量 public static final
//声明为final必须赋值
String name= "狮子";
//抽象方法 public abstract
//不能有方法体
void eat();
void run();
//静态方法
public static void sleep(){
System.out.println("狮子在睡觉");
}
public static void jump(){
System.out.println("狮子跳");
}
//默认方法
public default void fight(){
System.out.println("狮子在打架");
}
}
interface tiger{
//全局常量 public static final
//声明为final必须赋值
String name= "老虎";
//抽象方法 public abstract
//不能有方法体
void eat();
void run();
public default void fight(){
System.out.println("老虎在打架");
}
}
class fish{
public void fight(){
System.out.println("鱼群在打架");
}
8、内部类
- Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类.
- 内部类的分类:成员内部类(直接定义在类中) VS 局部内部类(方法内、代码块内、构造器内)
- 成员内部类(分类于是否static修饰)
- 作为外部类成员:
- 可以调用外部1结构
- 可以被4种权限修饰符、abstract修饰
- 作为一个类
- 可以定义属性、方法、构造器
- 可以被final、abstract修饰
如何实例化内部类?
//A为内部类,B为外部类
//静态
B.A aaa=new B.A();
aaa.XXX//调用方法属性之类的
//非静态
B bbb=new B();
B.A ccc= bbb.new A();