独立于对象之外的变量和方法
(1)为什么需要静态变量?
在实际开发场景中,处理问题时,会需要两个类在同一内存区域中共享一个数据,或共用一个方法,此时就需要使用到静态变量和静态方法
(2)什么是静态变量?
类变量也叫静态变量,静态属性,为该类所有对象共享的变量
访问修饰符 static 数据类型 变量名; //(推荐)
static 访问修饰符 数据类型 变量名;
(3)怎么使用静态变量?
类名.类变量名;(推荐)
对象名.类变量名;
(4)使用静态变量时需要注意的问题
(1)什么是静态方法?
访问修饰符 static 数据返回类型 方法名() {}
(推荐)static 访问修饰符 数据返回类型 方法名() {}
(2)怎么使用静态方法?
在满足访问修饰符的前提下
类名.类方法名
对象.类方法名
(3)使用静态方法时需要注意的问题
this
,super
)public static void main(String[] args) {}
(1)理解main方法
public
static
String[] args
的意义:传递参数——在控制台输入:java 文件名 参数一 参数一 ...
(2)说明
{}
(1)代码块
代码块属于类中的成员(类的一部分)
类似于方法,将逻辑语句封装在方法体中,通过{}
包围起来
但是与方法不同,代码块没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类,或创建对象时隐式调用
(2)语法
修饰符 { 代码; };
;
可以省略(3)三种代码块
(1)静态代码块随着类的加载而执行,且只执行一次
(2)类什么时候被加载
(3)构造代码块在创建实例时被隐式地调用,创建一次,调用一次
(4)代码块在创建一个对象时,在一个类中的调用顺序是
(5)构造器前隐含了super()
构造器,和调用构造代码块,即父类构造器优先于调用本类构造代码块
(6)创建一个子类对象时,他们的静态代码块,静态属性初始化,构造代码块,普通属性初始化,构造方法的调用顺序如下:
(7)静态代码块只能直接调用静态成员,构造代码块可以调用任意成员
(1)构造器的补充机制,相当于另外一种形式的构造器,可以做初始化的操作
(2)如果多个构造器中都有重复语句,可以抽取到代码块中,提高代码的重用性
(1)什么是设计模式?
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式
(2)什么是单例模式?
所谓的单例模式,即单个实例,指采取一定的方法保证在整个的软件系统中只能存在一个实例,并且该类只提供一个取得其对象的方法
(3)饿汉式
getInstance()
public class SingleTon01 { //通过类调用静态方法获取对象 GirlFriend instance = GirlFriend.getInstance(); } class GirlFriend { private String name; //2、在类的内部创建对象 //为了能在静态方法中使用,需要将其修饰为静态方法 private static GirlFriend gf = new GirlFriend("小花花"); //保证只有一个实例对象 //1、构造器私有化 private GirlFriend(String name) { this.name = name; } //3、提供暴露的静态公共方法,返回gf对象 public static GirlFriend getInstance() { return gf; } }
(4)懒汉式
public class SingleTon02 { } class Cat { private String name; //不直接实例化 private static Cat cat; private Cat(String name) { this.name = name; } //懒汉式——在静态的公共方法中进行对象的实例化 public static Cat getInstance() { if (cat == null) {//保证单例 cat = new Cat("小可爱"); } return cat; } }
(5)比较
可以用来修饰类,属性,方法和局部变量
(1)当不希望类被继承时,用final修饰——修饰类
(2)当不希望父类的某个方法被子类重写时,用final——修饰方法
(3)当不希望类的某个属性被修改时,用final——修饰属性
(4)不希望某个局部变量被修改——修饰局部变量
(1)final修饰的属性又叫做常量,一般用XX_XX_XX来命名
(2)final修i是的属性在定义时,必须赋初始值,且不能修改
赋值的位置
public final double TAX_RATE = 0.08;
类的成员变量,局部变量在使用前初始化即可
(3)如果final修饰的属性为静态的,则初始化位置只能在如下所示位置
位置
类加载——》静态代码块执行
(4)final修饰类不能继承,但可以实例化对象
(5)如果不是final类,含有final方法,则该方法不能重写,但可以被继承
(6)final类中所有的方法被隐式设置为final方法
(7)final不能修饰构造方法
(8)final和static往往搭配使用,效率更高,不会导致类加载(底层做了优化)
(9)包装类(Integer,Double,Float,Boolean)都是final类,String也是final类
父类方法的不确定性
当父类的某些方法需要声明,但又不确定该如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类
抽象类除了继承毫无意义
(1)用abstract关键字来修饰一个类时,类为抽象类
语法:访问修饰符 abstract class 类名 {}
(2)抽象方法
语法:访问修饰符 abstract 返回类型 方法名(形参列表);
(无方法体)
(3)抽象类的价值在于设计,是设计者设计好后,让子类实现抽象类
(4)抽象类为考官常考知识点,子啊框架和设计模式中涉及较多
(1)抽象类不能实例化
(2)抽象类不一定要有抽象方法,而且可以有实现方法
(3)有抽象方法一定是抽象类
(4)abstract只能修饰类和方法
(5)抽象类仍然是类,可以有任意类可以有的成员
(6)抽象方法不能有方法体
(7)如果一个类继承了抽象类,则必须实现(重写)抽象类的所有抽象方法,除非它也声明为abstract类
(8)抽象方法不能使用private,final和static来修饰,因为与重写向违背
抽象类体现的就是一种模板模式的设计,抽象类作为子类的通用模板
子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为
(1)当内部功能一部分实现是确定的,一部分实现是不确定的,这时可以把不确定的部分暴露出去,由子类实现
(2)编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式
public class AbstractExercise01 { public static void main(String[] args) { //创建员工和经理 CommonEmployee commonEmployee = new CommonEmployee("jack", 51, 2000); Manager manager = new Manager("tony", 52, 20000, 100000); commonEmployee.work(); manager.work(); } } //抽象类 abstract class Employee { private String name; private int id; private double salary; public Employee(String name, int id, double salary) { this.name = name; this.id = id; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public abstract void work(); } class Manager extends Employee { private double bonus;//奖金 public Manager(String name, int id, double salary, double bonus) { super(name, id, salary); this.bonus = bonus; } public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } @Override public void work() { System.out.println("经理" + this.getName() + "正在工作中..."); } } class CommonEmployee extends Employee { public CommonEmployee(String name, int id, double salary) { super(name, id, salary); } @Override public void work() { System.out.println("员工" + this.getName() + "正在工作中..."); } }
接口就是一个标准
(1)接口被用来描述一种抽象(用来实现多继承)
(2)接口被用来实现抽象,抽象类也被用来实现抽象,为什么一定要用接口,二者之间的区别是什么?
(3)为不同类顺利交互提供标准
接口就是给出一些没有实现的方法,封装到一起,在某个类要使用的时候,根据具体情况,实现方法
//定义接口 interface 接口名 { //属性 //方法 } //实现 class 类名 implements 接口名 { //属性 //方法 //必须实现的接口的抽象方法 }
指定标准,接口是需求的实际体现
(1)接口不能被实例化
(2)接口中的所有方法是public方法,接口中抽象方法可以不用abstract修饰,因为interface中方法默认为public abstract修饰
(3)一个普通类实现接口,就必须将该接口的所有方法都实现
(4)除非声明为抽象类,上(3)可不用全部实现
(5)一个类可以实现多个接口
(6)接口中的属性 ,只能是final
,而且是public static final
修饰
(7)接口属性的访问:接口名.属性;
(8)接口不能继承类,但可以继承多个别的接口
(9)接口修饰符和类一样,只能是public和默认的
(1)解决问题不同
(2)接口比继承更灵活
is-a
关系,子类是一个父类like-a
,类像一个接口(3)接口在一定程度上实现代码解耦
接口规范性+动态绑定
(1)参数的多态性
接口引用可以指向实现了接口的类的对象
(2)多态数组
public class Arr { public static void main(String[] args) { //多态数组 Usb[] usbs = new Usb[2]; usbs[0] = new Phone(); usbs[1] = new Camera(); //调用 for(int i = 0; i < usbs.length; i++) { usbs[i].work;//动态绑定 if (usbs[i] instenceof Phone) { ((Phone)usbs[i]).call();//向下转换:前提是引用指向的对象本来就是Phone类 } } } } //接口 interface Usb { void work(); } class Phone implements Usb { public void call() { "手机打电话".sout;//输出 } //实现 public void work() { "手机工作中".sout; } } class Camera implements Usb { public void work() { "相机工作中".sout; } }
(3)接口的多态传递
interface IH{} //IG 继承 IH interface IG extends IH {} //Teacher类实现IG接口的同时也实现了IH接口 class Teacher implements IG {} //主方法简写 main { IG ig = new Teacher();//一个IG接口的引用指向了一个Teacher类的实例 IH ih = new Teacher();//一个IH接口的引用指向了一个Teacher类的实例 }
每个内部类都能独立地实现一个接口,无论外部类是否实现了接口,对内部类而言都不影响,从而结局了Java多继承的问题
一个类的内部完整地嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类为外部类,是类的第五大成员(属性,方法,构造器,代码块,内部类)
最大的特点:可以直接访问外部类的私有属性,并且可以体现类之间的层级关系
class 外部类 { class 内部类 { } } class 外部其他类 { }
定义在外部类成员的位置上的内部类,按静态非静态划分为
成员内部类
静态内部类
定义在外部类成员的局部位置上的内部类,按有无类名区分为
外部类的成员位置,且非static
(1)可以直接访问外部类的所有成员,包含私有的
(2)地位为成员,则可以添加任意访问修饰符
(3)作用域:和外部其他类一样,整个类体
(4)成员内部类访问外部类:直接访问
(5)外部类访问成员内部类成员:在外部类里建立成员内部类对象,再调用
(6)外部其他类访问成员内部类成员
外部类.内部类 引用 = 外部类对象.new 内部类(实参列表);
(7)外部类和内部类成员重名时,就近原则,若要访问外部类——外部类名.this.成员;
外部类名.this
:表示指向外部类的对象
外部类的成员位置,为静态
(1)可以访问外部类所有静态成员,不能访问非静态成员
(2)可以添加任意修饰符
(3)作用域:整个类体
(4)静态内部类直接访问外部类成员
(5)外部类访问静态内部类成员:实例化静态内部类一个对象,再调用、
静态内部类只是说明该类属于外部类,而不属于外部类实例化的对象,而静态内部类的非静态成员,依然和静态内部类的对象相联系,所以需要实例化静态内部类对象后再调用目标成员
(6)外部其他类访问静态内部类
外部类.静态内部类 引用 = new 外部类.静态内部类(); 引用.成员;
静态成员可以通过类名来调用,静态内部类为静态成员,ps:静态内部类的成员不一定为静态
(7)外部类和内部类成员重名时,就近原则,若要访问外部类——外部类名.this.成员;
通常在方法中,有类名
(1)可以直接访问外部类的所有成员,包含私有的
(2)地位为一个局部变量,不能使用权限修饰符,但可以使用final关键字
(3)作用域:仅在定义它的方法或代码块中
(4)局部内部类访问外部类成员:直接访问
(5)外部类访问局部内部类:满足作用域的条件下(即在方法中),创建对象再访问
(6)外部其他类无法访问局部内部类:因为局部内部类为一个成员变量
(7)外部类和内部类成员重名时,就近原则,若要访问外部类——外部类名.this.成员;
匿名的局部内部类,不是没名,而是系统自动分配类名
(1)语法
new 类或接口(参数列表) { 类体; }; //底层运行逻辑 class 外部类名$02 implements 类或接口 {//实现了类接口或继承了类 类体; } new 外部类名$02();//实例化一个匿名内部类的对象
//例子 public class AnonymousInnerClass {//外部其他类 public static void main(String[] args) { Outer outer = new Outer(); outer.method(); } } class Outer {//外部类 private int n1 = 10;//属性 public void method() {//外部类的方法中建立内部类 /** * 1、需求:使用A接口,并创建对象 * 2、传统方式:创建一个类重写方法,实现接口,并创建对象 * 3、若tiger类只使用一次,后面不再使用 * 4、解决方案:使用匿名内部类,来简化开发 * */ //基于接口的匿名内部类 /** * 匿名内部类基于接口的解析 * 1、tiger的编译类型为:IA接口类型 * 2、tiger的运行类型为:匿名内部类,匿名内部类并非没有名字,只是由系统分配类名,底层如下 * -IA() {类体};:创建了一个实现了接口的匿名内部类,注意为一个语句,需要分号“ ; ” * class Outer$01 implements IA { * 类体 * }; * new IA() {}; :创建了一个匿名内部类的对象 * new Outer$01(); * IA tiger = new IA() {}; * 将实例化的一个实现了A接口的匿名内部类的对象的地址传递给tiger *3、匿名内部类使用一次,就不能再使用了,但是tiger可以重复使用 * */ IA tiger = new IA() {//基于接口的匿名内部类 @Override public void cay() { System.out.println("老虎嗷嗷叫"); } }; //在外部类中,在内部类作用域即方法中,调用内部类的成员——创建一个指向内部类对象的引用,用对象来调用方法 tiger.cay(); // Tiger tiger = new Tiger(); // tiger.cay(); //基于类的匿名内部类 /** * 匿名内部类基于类的解析 * 1、father的编译类型:Father * 2、father的运行类型:Outer$2 father对象的运行类型:class com.zyhstu.innerclass.Outer$2 * -Father("jack") {类体};:创建了一个继承了Father父类的Outer$2子类 * class Outer$2 extends Father { * 类体; * }; * -new Father("jack") {类体};:创建一个匿名内部类Outer$2的对象,并将jack自动传给Father的构造器 * new Outer$2() {类体}; * -Father father = new Father("jack") {}; * 实例化一个继承了Father父类的Outer子类的对象,并将地址传递给一个Father的引用 * */ Father father = new Father("jack") { @Override public void test() { System.out.println("匿名内部类重写了test()方法"); } }; father.test(); System.out.println("father对象的运行类型:" + father.getClass()); //基于抽象类的匿名内部类 Animal animal = new Animal() { @Override void eat() { System.out.println("小狗吃骨头"); } }; animal.eat(); } } interface IA { public void cay(); } //class Tiger implements IA { // @Override // public void cay() { // System.out.println("老虎嗷嗷叫"); // } //} // //class Dog implements IA { // @Override // public void cay() { // System.out.println("小狗汪汪叫"); // } //} class Father {//外部其他类 public Father(String name) {//构造器 } public void test() {//方法 } } //抽象类 abstract class Animal { abstract void eat(); }
(2)匿名内部类的使用
new 类或接口(实参列表) { 类体; }.方法(方法实参);
类名 引用 = new 类或接口(实参列表) { 类体; } 引用.方法(方法实参);
(3)注意事项
外部类名.this.成员;