static
什么是static?
- 叫静态,可以修饰成员变量,成员方法。
成员变量按照有无static修饰,分为两种:
- 类变量:有static修饰,属于类,在计算机里只有一份,会被类的全部对象共享。
在什么情况下使用:数据只需要一份,且需要被共享时。
- 实例变量(对象的变量):无static修饰,属于每个对象的。
在什么情况下使用:每个对象都需要有一份,数据各不同。
//1.类变量名的用法
//类名.类变量(推荐)
Student.name="袁华";
//对象.类变量(不推荐)
Student s1=new Student();
s1.name="马冬梅";
Student s2=new Student();
s2.name="秋雅";
System.out.println(s1.name);//结果为:秋雅
//对象.实例变量
s1.age=18;
s2.age=25;
System.out.println(s1.age);//结果为:18
工具类是什么?
- 工具中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的。
使用类方法来设计工具类的好处是什么?
- 提高了代码复用性,调用方便,提高了开发效率。
注意:因为工具类不需要创建对象,建议将工具类的构造器私有。
使用类方法,实例方法的注意事项
- 类方法中可以直接访问类的成员,不可以直接访问实例成员。
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员。
- 实例方法中可以出现this关键字,类方法中不可以出现this关键字。
代码块
代码块概述:
- 代码块是类的五大成分之一(成员变量,构造器,方法,代码块,内部类)。
代码块分为两种:
静态代码块:
- 格式:static{ }
- 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会加载一次。
- 作用:完成类的初始化,例如:对类变量的初始化赋值。
实例代码块:
- 格式:{ }
- 特点:每次创建对象时,会执行实例代码,并在构造器前执行。
- 作用:和构造器一样,都是用来完成对象的初始化,例如:对实例变量进行初始化赋值。
设计模式
什么是设计模式?
- 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来,就叫做设计模式。
单列设计模式:
确保一个类只有一个对象。
写法:
- 把类的构造器私有。
- 定义一个类变量记住类的一个对象。
- 定义一个类方法,返回对象。
饿汉式单列特点:在获取类的对象时,对象已经创建好了。
懒汉式单例设计模式:
- 拿对象时才开始创建对象。
写法:
- 把类的构造器私有。
- 定义一个类用于存储对象。
- 提供一个类方法,保证返回的是同一个对象。
面向对象三大特征之二:继承
什么是继承?
- Java中提供了一个关键字extends,用这个关键字可以让一个类和另一个类建立起父子关系。
形式:
public B extends A{
} //其中B类叫作子类(派生类)
//A类成为父类(基类或超类)
继承的特点和好处:
- 子类能继承父类的非私有成员(成员变量,成员方法) 。
- 减少重复代码的书写(好处)。
继承后成员的创建:
- 子类的对象是由子类和父类共同完成的。
继承相关的注意事项
1.Java是单继承的:一个类只能继承一个直接父类;Java中的类不支持多继承,但是支持多层继承。
2.Object类是Java中所有类的祖宗。
权限修饰符:
public , private ,protected , 缺省
什么是权限修饰符?
- 就是用来限制类中的成员(成员变量,成员方法,构造器,代码块...)能够被访问的范围。
权限修饰符各自的作用:
修饰符 | 在本类中 | 在一个包下的其他类里 | 任意包下的子类里 | 任意包下的任意类里 |
private | √ | |||
缺失 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
private < 缺省 < protected < public
什么是方法重写?
- 当子类觉得父类中某个方法不好时,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的这个方法,就是方法重写。
- 注意:重写后,方法的访问,Java会遵循就近原则。
方法重写的其他注意事项:
- 重写小技巧:使用Override注解,他可以指定Java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。
- 子类重写父类方法时,访问权限必须大于或等于父类该方法的权限。(public>protected>缺省)
- 重写的方法返回值类型,必须与被重写方法返回值类型一样,或者范围更小。
- 私有方法,静态方法不能被重写,如果重写会报错。
1.在子类中访问其他成员(成员变量,成员方法),是依照就近原则。
- 先在子类局部范围找。
- 然后子类成员范围找。
- 然后父类成员范围找,如果父类范围还未找到就报错。
2.如果子父类中,出现重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类怎么办?
- 可以通过super关键字,指定访问父类成员:super.父类成员变量/成员方法
子类构造器的特点
- 子类的全部构造器,都会先调用父类的构造器,再执行自己的。
子类构造器如何实现调用父类构造器的?
- 默认情况下,子类全部构造器的第一行代码都是super ( )(写不写都有),他会调用父类的无参数构造器。
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(.....),指定去调用父类的有参数构造器。
补充知识
- 任意类的构造器中是可以通过this(....),去调用该类的其他构造器。
public Student(String name,int age){
this(name,age,"黑马学校"); //调用了下面的那个构造器
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
SchoolName = schoolName;
}
this(....)和super(...)的注意事项:
- this(...)和super(...)都要放在构造器的第一行,因此有了this(...)就不写有super(...),反之亦然。
面向对象的三大特征之三:多态
认识多态:
1.什么是多态?
- 多态是在继承/实现情况下的一种现象,表现为:对象多态,行为多态。
2.多态的具体代码体现:
3.多态的前提:
有继承/实现关系;存在父类引用子类对象;存在方法重写。
4.多态的一个注意事项:
多态是对象,行为的多态,Java中的属性(成员变量)不谈多态。
使用多态的好处:
1.好处:
- 在多态形式下,右边对象是解耦合的,更便于扩展和维护。
people p1=new Student(); //右边部分可以随时更换
p1.run;
- 在定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强,更便利。
2.坏处:
- 多态下不能直接调用子类的独有方法。
类型转换:
1.类型转换:
- 自动类型转换:父类 变量名 = new 子类();people p = new Student();
- 强制类型转换: 子类 变量名=(子类)父类变量名;Student s=(Student) p;
2.强制类型转换的注意事项:
- 存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错。
- 运行时,如果发现对象的强转类型与真实类型不同,就会报类型转换异常(ClassCastException)的错误出来。
people p=new Teacher();
Student s=(Student) p;// 报错:ClassCastException
3.强转前,Java建议:
- 使用instanceof关键字,判断当前对象的真实类型,再进行强转。
public static void go(People p){
p.run;
if(p instanceof Student){
Student s=(Student) p;
s.test();
}else if(p instanceof Teacher){
Teacher t=(Teacher) p;
t.test();
final
1.final:
- final关键字是最终的意思,可以修饰(类,方法,变量 )。
- 修饰类:该类被称为最终类,特点是不能被继承
- 修饰方法:该方法被称为最终方法,特点是不能被重写
- 修饰变量:该变量只能被赋值一次
2.final修饰变量的注意:
- final修饰基本类型的变量,变量存储的数据不能被改变。
- final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以改变的 。
3.常量 :
- 使用了static final修饰的成员变量就称为常量
- 作用:通常用于记录系统的配置信息
public class Constant{
public static final String SCHOOL_NAME="传智教育";
}
注意!常量名的命名规范:建议使用大写英文字母,多个单词用下划线连接起来。
4.使用常量记录系统配置信息的优势,执行原理:
- 代码可读性更好,可维护性更好。
- 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成字面量,这样可以保证使用常量和直接使用字面量的性能是一样的。
抽象类
1.什么是抽象类?
- 在Java中有一个关键字叫:abstract,他就是抽象的意思,可以用它修饰类,成员方法。
- abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。
public abstract class A {
//抽象方法:必须用abstract修饰,只有方法签名,不能有方法体
public abstract void run();
}
2.抽象类的注意事项,特点:
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量,方法,构造器)抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
3.抽象类的应用场景和好处?
- 父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态。
接口
1.认识接口
- Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊结构:接口。
public interface 接口名{
//成员变量(常量)
//成员方法(抽象方法)
}
- 注意:接口不能创建对象;接口是用来被类实现(implements)的 ,实现接口的的类称为实现类。
修饰符 clsaa 实现类 implements 接口1,接口2,接口3...{
}
- 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部全部接口的全部抽象方法,否则实现类就要定义成抽象类。
2.接口的好处(重点):
- 弥补了类单继承的不足,一个类可以同时实现多个接口。
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。一个类可以实现多个接口,一个接口也可以实现多个类。
3.JDK8开始,接口新增的方法:
- 默认方法:使用default修饰,使用实现类的对象调用
- 静态方法:使用static修饰,必须用当前接口名调用。
- 私有方法:private 修饰,jdk9才开始有,只能在接口内部被调用。
- 他们都会默认被public修饰。
default void test1(){ System.out.println("---默认方法---"); } private void test2(){ System.out.println("私有方法"); } static void test3(){ System.out.println("静态方法"); }
4.接口的多继承:
- 一个接口可以同时继承多个接口。
public interface E extends A, B,C{ }//接口继承多个接口 class M implements A,B,C{ }//类实现多个接口
5.接口的其他注意事项:
-
一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持继承。
-
一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
-
一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
-
一个类实现多个接口,多个接口中存在同名默认方法,可以不冲突,这个类重写该方法即可。
内部类
内部类 :
- 是类的五大成分之一 (成员变量,方法,构造器,内部类,代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
- 当一个类的内部包含一个完整的事物,且这个事务没有必要单独设计时,就可以把这个事物设计成内部类。
public class Car{ public class Engine{ } }
内部类有四种形式:
-
成员内部类
-
静态内部类
-
局部内部类
-
匿名内部类(重点)
1.成员内部类
- 就是类中的一个普通成员,类似于之前学的普通的成员变量,成员方法。
public class Outer{
public class Inner{
}
}
如何创建对象:
外部类名.内部类名 对象名=new 外部类(...)new 内部类(...)
(1)成员内部类中访问其他成员的特点:
- 和之前学过的实例方法一样,成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员。
- 可以在成员内部类的实例方法中,拿到当前外部类对象,格式是:外部类名.this
2.静态内部类
- 有static修饰的内部类,属于外部类自己持有的。
public class Outer{
//静态内部类
public static class Inner{
}
}
(1)创建对象的格式:
- 外部类名.内部类名 对象名=new 外部类.内部类(...)
- Outer.Inner in=new Outer.Inner(...)
(2)静态内部类访问外部类成员的特点:
- 可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
3.局部内部类
- 定义在方法中,代码块中,构造器等执行体中
4.匿名内部类
- 最终目的是简化代码。匿名内部类不是主动去去用,而是在有需求的时候去用
- 就是一种特殊的局部内部类;所谓匿名,就是程序员不需要为这个类声明名字。
new 类接口(参数值){
类体(一般是方法重写)
}
public class Animal {
new Animal(){
@Override
public void cry{
}
}
2.特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
3.作用:用于更方便创建一个子类对象。
匿名内部类的开发场景:
- 匿名内部类通常作为一个参数传输给对象。
public static void main(String[] args) { // Swimming s1 = new Swimming(){ // @Override // public void swim() { // System.out.println("狗🏊飞快~~~~"); // } // }; // go(s1); go(new Swimming(){ @Override public void swim() { System.out.println("狗🏊飞快~~~~"); } }); } // 设计一个方法,可以接收swimming接口的一切实现类对象进来参加游泳比赛。 public static void go(Swimming s){ System.out.println("开始-----------------------"); s.swim(); } } // 猫和狗都要参加游泳比赛 interface Swimming{ void swim(); }
枚举
- 枚举是一种特殊的类。
枚举类的格式:
修饰符 enum 枚举类名{
名称1,名称2,....;
其他成员......
}
注意:
- 枚举类中的第一行,只能写一些合法的标志符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
- 枚举类的构造器都是私有的,不能对外创建对象。
- 枚举类提供一个一些额外的API。
- 枚举都是最终类,不可以被继承。
- 枚举类中,从第二行开始可以定义其他各种成员。
- 编译器为枚举新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从Enum类中也会继承一些方法。
泛型
?通配符,在使用泛型时可以代表一切类型
1.认识泛型
- 定义类、接口、方法时,同时声明一个或者多个类型变量(如:<E>),称为泛型接口,泛型方法,他们统称为泛型。
public class ArrayList<E>{
...
}
- 作用:泛型提供了在编译阶段约束所操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
- 泛型本质:把具体的数据类型作为参数传给类型变量。
2.泛型类
修饰符 class 类名 <类型变量,类型变量...>{
}
public class ArrayList<E>{
}
3.泛型接口
修饰符 interface 接口名 <类型变量,类型变量...>{
}
public interface A<E>{
}
4.泛型方法
修饰符 <类型变量,类型变量...> 返回值类型 方法名(形参列表){
}
public static <T> void test(T t){
}
通配符:
- 就是“?”,可以在使用泛型的的时候代表一切类型;E、K、K、V是在定义泛型的时候使用的。
泛型的上下限:
- 泛型上线:?extends Car : ?能接受的必须是Car或是其子类。
- 泛型下线:? super Car : ?能接受的必须是Car或是其父类。
泛型的擦除问题和注意事项:
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件就不存在泛型了,这就是泛型擦除。
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。