目录
一.类变量和类方法(static)
1.类变量
- 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
- 利用static修饰符创建类变量,利用 类名.类变量名 或 对象名.类变量名 访问类变量(访问权限和范围与普通变量相同)
-
class Animal{ public static int dog = 0; } class start{ Animal.dog=1; }
- 静态变量在类加载的时候就已经创建,所以没有创建实例也可访问
2.类方法
当方法使用了static修饰后就成为了静态方法,可以访问静态变量,访问方式和范围与属性类似,当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率,如开发自己的工具类时
注意:
- 类方法和普通方法都随着类的加载而加载,将结构信息存储在方法区
- 类方法中无this的参数(不允许使用和对象有关的 关键字比如this和super),普通方法中隐含着this的参数
- 类方法中只能访问静态变量和静态方法
- 普通成员方法既可以访问普通变量和方法也可以访问静态变量和方法
- 静态方法不具有多态性,如果子类中静态方法的签名与父类中静态方法的签名相同,那么父类中的静态方法将被隐藏,而不是被重写
二.main 方法语法
1.解释main方法的形式
public static void main(String[] args){}
- Java虚拟机需要调用main ()方法,所以该方法的访问权限必须是public
- jvm在执行main方法是不需要创建对象,所以该方法必须是static
- 该方法接收String类型的数组参数,该数组中保存执行Java命令时传递给所运行时的类的参数
- Java指向的程序参数
2.特别提示
- 在main()方法中,我们可以直接调用 main 方法所在类的静态方法或静态属性。
- 但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
三.代码块
1.基本介绍
代码块又称为初始化块,属于类中的成员(即 类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来,但与方法不同,没有方法名,返回,参数,只有方法体,而且不用通过对象或类显示调用,而是加载类时,或创建对象时隐式调用。
2.基本语法
[修饰符]{
//代码
}
注意:
- 修饰符可选,且如果有,只能为static
- 代码块根据是否有static分为两类,静态代码块和普通代码块
- 逻辑语句可以为任何逻辑语句(输入输出,方法调用,循环判断等)
- ;可有可无
3.代码块的作用
相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化操作。当多个构造器中有重复语句,可以抽取到代码块中,提高代码的复用性。代码块的调用优先级高于构造器
4.代码块的注意事项
1) static 代码块也叫静态代码块,作用就是对类进行初始化,而且随着类的加载而执行,并且只会执行一次,而普通代码块每创建一个对象就执行一次。
2)类被加载的时间
- 创建对象实例时(new)
- 创建子类对象实例,父类也会被加载
- 使用类的静态成员时(静态属性,静态方法)
3)普通代码块在创建对象实例时,会被隐式的调用,被创建一次调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。
4)创建一个对象时,在一个类调用的顺序是:
- 调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化的调用优先级时一样的,如果有多个,则按顺序调用)
- 调用普通代码块和普通属性初始化(多个同上)
- 调用构造方法
5)构造器的最前面隐含了super()和调用普通代码块,静态相关的代码块,属性初始化在类加载时就已经执行完毕,因此优先于构造器和普通代码块执行。
6)创建一个子类对象时,静态代码块属性,普通代码块属性,构造方法的调用顺序(面试):
- 父类的静态代码块和静态属性初始化(按序执行)
- 子类的静态代码块和静态属性初始化(按序执行)
- 父类的普通代码块和普通属性初始化
- 父类的构造方法
- 子类的普通代码块和普通属性初始化
- 子类的构造方法
7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员
四.单例设计模式
单例设计模式就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
1.饿汉式
/*
饿汉式单例设计
1.将构造器私有化
2.在类的内部创建一个静态私有对象
3.向外部暴漏一个公共静态方法获取对象
特点:对象在类被调用时自动创建,可能造成内存浪费
*/
class hungerCat {
private String name;//属性
private static hungerCat hgc = new hungerCat("eh");
private hungerCat(String name) {
this.name = name;
}
public static hungerCat getinfo() {
return hgc;
}
}
2.懒汉式
/*
懒汉式单例设计
1.将构造器私有化
2.在类的内部创建静态私有对象属性
3.提供公共静态对象返回对象
特点:只有当用户调用方法时才返回对象,再次调用时会返回上次创建好的对象
*/
class lazyCat{
private String name;
private static lazyCat lzc;
private lazyCat(String name) {
this.name = name;
}
public static lazyCat getinfo(){
if (lzc == null) //如果对象还未创建
lzc=new lazyCat("lh");
return lzc;
}
}
3.饿汉式vs懒汉式
- 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式何时使用何时创建
- 饿汉式不存在线程安全问题,懒汉式存在
- 饿汉式存在浪费资源的可能,如果一个实例对象都没有使用,饿汉式创建的对象就浪费了
五.final关键字
1.基本介绍
final可以修饰类,属性,方法和局部变量。常用场景
- 当不希望类被继承时
- 当不希望父类的某个方法被子类覆盖/重写
- 当不希望类的某个属性的值被修改
- 当不希望某个局部变量被修改
2.final注意事项
1)final修饰的属性又叫常量,一般用XX_XX命名
2)final修饰的属性在定义时,必须赋初值,且不能再被修改,赋值位置可以为:
- 定义时
- 在构造器中
- 在代码块中
3)如果final修饰的属性是静态的,则初始化位置只能为:
- 定义时
- 静态代码块中(不能在构造器中赋值)
4)final类不能被继承,但能被实例化对象
5)如果类不是final类,但含有final方法,则该方法不能重写,但可以被继承
6)final不能修饰构造器
7)final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理
public class text {
public static void main(String[] args) {
System.out.println(BBB.num);
}
}
class BBB {
public final static int num = 10000;
static {
System.out.println("BBB 静态代码块被执行");
}
}
结果:
8)包装类都是final类。
六.抽象类
当父类的某些方法需要声明,但是又不确定如何是实现时,可以将其声明为抽象(abstract)方法,抽象方法就是没有实现的方法(没有方法体),此时该父类就是抽象类(当一个类中存在抽象方法时,需要将该类声明为abstract类),一般来说抽象类会被继承,并由子类实现具体抽象方法。
1.抽象类的介绍
1)用abstract关键字修饰一个类时,这个类就叫抽象类
[访问修饰符] abstract 类名{
}
2)用abstract关键字修饰一个方法时,这个方法就是抽象方法
[访问修饰符] abstract [返回类型] 方法名(参数列表);//没有方法体
3)抽象类的价值更多在于设计,是设计者设计好后,让子类继承并实现抽象类
abstract class Animal{
String name;
int age;
String color;
abstract public void cry();
}
2.抽象类的关键事项
1) 抽象类不能被实例化
2) 抽象类不一定要包含抽象方法,即抽象类可以没有抽象方法
3) 一旦类包含了抽象方法,则这个类必须声明为抽象类
4) abstract只能修饰类和方法,不能修饰属性和其他
5) 抽象类的本质仍是类,可以拥有任意成员(非抽象方法,构造器,静态属性等等)
6) 抽象方法不能有主体
7) 如果一个类继承了抽象类,则它必须实现抽象类的所以抽象方法,除非它也是一个抽象类
8) 抽象方法不能使用private,final和static来修饰,因为这些关键字都是和重写相违背的
七.模板设计模式
1.基本介绍
抽象类体现的是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展,改造,但子类总体上会保留抽象类的行为方式.
2.应用场景
1) 当功能内部的一部分实现是确定的,一部分实现是不确定的.这时可以把不确定的部分暴漏出去,让子类去实现.
2) 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式.
八.接口
1.基本介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
interface 接口名 {
//属性
//抽象方法
}
class 类名 implements 接口名{
//类的属性
//类的方法
//必须实现的接口的抽象方法
}
接口是更加抽象的抽象类,抽象类里可以有非抽象方法,但接口里所有方法都必须是抽象方法(无方法体){jdk7.0},接口体现了程序设计的多态和高内聚低耦合的设计思想. jdk8后 接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现.
2.接口注意事项
1) 接口不能被实例化
2) 接口中所有的方法是public方法,接口中抽象方法可以不用abstract修饰(本身带有隐藏的abstract关键字)
3) 一个普通类实现接口,必须将接口的所有方法实现
4) 抽象类实现接口,可以不用实现接口的方法
5) 一个类同时可以实现多个接口
6) 接口中的属性,默认为public static final修饰 ,必须初始化
7) 接口中的属性的访问形式:接口名.属性名
8) 接口不能继承其它的类,但是可以继承多个别的接口
interface B{}
interface C{}
interface A extends B,C{}
9) 与类一样,接口的修饰符只能是public和默认
3.实现接口vs继承类
当子类继承了父类,就自动拥有父类的功能,而如果需要拓展功能,不能另外继承,但可以通过实现接口进行拓展. 可以理解实现接口是对Java单继承机制的补充
1) 接口和继承解决的问题不同
继承:解决代码的复用性和可维护性.
接口:设计好各种规范(方法),让其它类去实现这些方法,使程序更加灵活
2) 接口在一定程度上实现代码解耦(接口规范性+动态绑定机制)
4.接口的多态性
1) 多态参数
2) 多态数组
3) 多态传递
九.内部类
1.基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员[属性、方法、构造器、代码块、内部类],内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
2.基本语法
class Outer{
class Inner{
}
}
class Other{
}
package com;
public class InnerClass {
public static void main(String[] args) {
}
}
class Outer { //外部类
private int n1 = 100;//属性
public Outer(int n1) {//构造器
this.n1 = n1;
}
public void m1() {//方法
System.out.println("m1()");
}
{//代码块
System.out.println("代码块...");
}
class Inner { //内部类, 在 Outer
}
}
3.内部类的分类
如果定义类在局部位置(方法中/代码块) :
(1) 局部内部类(有类名)
(2) 匿名内部类(没有类名)
定义在成员位置:
(1) 成员内部类(没有static修饰)
(2) 静态内部(使用static修饰)
4.局部内部类的使用
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
1) 可以直接访问外部类的所有成员,包含私有的
2) 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final 修饰,因为局部变量也可以使用final
3) 作用域: 仅仅在定义它的方法或代码块中
4) 局部内部类---访问---->外部类的成员[访问方式:直接访问]
5) 外部类---访问---->局部内部类的成员 [访问方式:创建对象,再访问(注意:必须在作用域内)]
记住:
- 局部内部类定义在方法中/代码块
- 作用域在方法体或者代码块中
- 本质仍然是一个类
6) 外部其他类---不能访问----->局部内部类(因为 局部内部类地位是一个局部变量)
7) 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员) 去访问
5.匿名内部类的使用
1) 基本语法
/*
本质是类,该类没有名字,同时也是一个对象
*/
new 类或接口(参数列表){
类体
};
interface Infa{
void fuc();
}
class Outer{
private int n=10;//属性
public void method(){
Infa dog=new Infa(){
@Override
void fuc() {
//......
}
};
//jdk底层在创建匿名内部类Outer$1,立即创建了Outer$1实例,并且把地址返回给dog;
//匿名内部类使用一次,就不能再使用
//参数列表的内容传给匿名内部类的构造器
}
}
2) 匿名内部类既是一个类的定义,同时本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征.
3) 可以直接访问外部类的所有成员,包含private
4) 不能添加访问修饰符,因为本质是一个局部变量
5) 作用域:定义它的方法或代码块中
6) 局部内部类---访问---->外部类的成员[访问方式:直接访问]
7) 外部其他类---访问---->局部内部类的成员[无法访问]
8) 外部类和内部类成员重名时,默认遵循就近原则,如果想访问外部类的成员 使用外部类名.this.成员访问
匿名内部类的最佳实践:当作实参直接传递
public class InnerClassExercise01 {
public static void main(String[] args) {
//当做实参直接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println("这是一副名画~~...");
}
});
//传统方法
f1(new Picture());
public static void f1(IL il) {
il.show();
}
}
}
interface IL {
void show();
}
6.成员内部类的使用
定义在外部类的成员位置,并且没有static修饰
其他与局部内部类相同
外部其他类使用成员内部类的两种方式
/ 第一种方式
// outer.new Inner(); 相当于把 new Inner()当做是 outer 成员
Outer.Inner inner = outer.new Inner();
// 第二方式 在外部类中,编写一个方法,可以返回 Inner对象
Outer.Inner innerInstance = outer.getInnerInstance();
7.静态内部类的使用
定义在外部类的成员位置,并且有static修饰
其他与局部内部类相同
外部其他类使用j静态内部类的两种方式
//方式 1
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer.Inner inner = new Outer.Inner10();
//方式 2
//编写一个方法,可以返回静态内部类的对象实例.
Outer.Inner inner = Outer.getInner();