1、static修饰符
1.1static修饰成员变量
static叫静态,可以修饰成员变量、成员方法
成员变量按照有无static修饰,分为两种
类变量 : 有static修饰,属于类,在计算机里只有一份,会被类的全部对象共享
- 在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。
- 在某个类中访问其他类里的类变量,必须带类名访问。不推荐使用对象名来访问
实例变量*(对象的变量): 无static修饰,属于每个对象的。
1.2static修饰成员方法
类方法 : 类方法最常见的应用场景是做工具类
- 提高了代码复用;调用方便,提高了开发效率。如Math就是一个类方法,提供不少计算方法
1.3static的注意事项
- 类方法中可以直接访问类的成员,不可以直接访问实例成员。
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员。
- 实例方法中可以出现this关键字,类方法中不可以出现this关键字的(不一定有这个类的实例对象)
1.4代码块
代码块是类的5大成分之一(成员变量、构造器、方法、代码块、内部类)。
代码块分为两种:
1.4.1静态代码块:
- 格式: static{}
- 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
- 作用:完成类的初始化,例如:对类变量的初始化赋值。
实例代码块:
- 格式:{)
- 特点: 每次创建对象时,执行实例代码块,并在构造器前执行。
- 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值
2.继承
2.1使用继承好处
- 减少了重复代码的编写,提高了代码的复用性。
2.2四种权限修饰符
- public
- private
- protected
- 缺省
private<缺省 < protected < public
2.3方法重写
2.3.1.方法重写是什么?
子类写了一个方法名称,形参列表与父类某个方法一样的方法去覆盖父类的该方法
2.3.2.重写方法有哪些注意事项?
- 建议加上:@Override注解,可以校验重写是否正确,同时可读性好
- 子类重写父类方法时,访问权限必须大于或者等于父类被重写的方法的权限。
- 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小
- 私有方法、静态方法不能被重写。
2.3.3.方法重写有啥应用场景?
当子类觉得父类的方法不好用,或者不满足自己的需求时,就可以用方法重写。
2.4子类访问成员的特点
2.4.1、在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的
- 先子类局部范围找。
- 然后子类成员范围找。
- 然后父类成员范围找,如果父类范围还没有找到则报错
2.4.2、如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?
可以通过super关键字,指定访问父类的成员: super.父类成员变量/父类成员方法
2.5 子类构造器
2.5.1.子类构造器有啥特点?
- 子类中的全部构造器,都必须先调用父类的构造器,再执行自己。
2.5.2、super(...)调用父类有参数构造器的常见应用场景是什么?
- 为对象中包含父类这部分的成员变量进行赋值。
2.5.3、this(...)的作用是什么?
- 在构造器中调用本类的其他构造器
2.5.3、this(...)和super(...)的使用需要注意什么?
- 都必须放在构造器的第一行(也就是不能先使用了super()然后使用this,因为父类的构造方法实现了两次)
2.6 面向对象的三大特征之三:多态
多态:多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态
2.6.1使用多态有什么好处?存在什么问题?
-
可以解耦合,扩展性更强;
-
使用父类类型的变量作为方法的形参时可以接收一切子类对象
定义方法时,使用父类类型作为形参,可以接收一切子类对象,扩展行更强,更便利。
public class Test2 {
public static void main(String[] args) {
// 目标:掌握使用多态的好处
Teacher t = new Teacher();
go(t);Student s = new Student(); go(s); } //参数People p既可以接收Student对象,也能接收Teacher对象。 public static void go(People p){ System.out.println("开始------------------------"); p.run(); System.out.println("结束------------------------"); }
}
2.6.2类型转换有几种形式?能解决什么问题?
- 自动类型转换(子类转为父类)
- 强制类型转换。(父类转子类)
目的:可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题
2.6.3强制类型转换需要注意什么?
- 存在继承/实现时,就可以进行强制类型转换,编译阶段不会报错
- 但是,运行时,如果发现对象的真实类型与强转后的类型不同会报错 (ClassCastException)
解决办法:使用instanceof判断当前对象的真实类型:然后在进行转换
//如果p接收的是子类对象
if(父类变量 instance 子类){
//则可以将p转换为子类类型
子类 变量名 = (子类)父类变量;
就可以调用子类的独有方法
2.7 final
final关键字是最终的意思,可以修饰类、修饰方法、修饰变量。
- final修饰类:该类称为最终类,特点是不能被继承
- final修饰方法:该方法称之为最终方法,特点是不能被重写。
- final修饰变量:该变量只能被赋值一次。
2.7.1常量
- 被 static final 修饰的成员变量,称之为常量。
- 通常用于记录系统的配置信息
- 程序编译后,常量会被"宏替换":出现常量的地方全部会被替换成其记住的字面量这样可以保证使用常量和直接用字面量的性能是一样的。
2.8抽象类和抽象方法
2.8.1 抽象类、抽象方法是什么样的?
都是用abstract修饰的;抽象方法只有方法签名,不能写方法体
2.8.2 抽象类有哪些注意事项和特点?
抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类
功能其实是更好地支持多态,把功能抽象出来,其实也和多态继承重写一个意思,不过这样的化更加专业,最佳实践。
2.8.3 抽象类的应用场景好处是什么?
父类知道每个子类都要做某个行为但每个子类要做的情况不是父类定,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态
2.8.4 抽象类的常见应用场景:模板方法设计模式
模板方法模式解决了多个子类中有相同代码的问题。具体实现步骤如下:
模板方法设计模式的写法
1、定义一个抽象类
2、在定2个方法
- 一个是模板方法: 把相同代码放里面去
- 一个是抽象方法:具体实现交给子类完成。
3、模板方法建议使用什么关键字修饰?为什么 - 建议使用final关键字修饰模板方法。也就是公共代码尽量不要让子类去修改
2.9接口:(俗称干爹)
接口中只有抽象方法和常量
public interface 接口名{
//成员变量(常量)
//成员方法(抽象方法)
}
一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
2.9.1接口的好处 (重点)
-
弥补了类单继承的不足,一个类同时可以实现多个接口。(代表类中包含多个功能)
-
让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
class Student{
}
interface Driver{
void drive();
}interface Singer{
void sing();
}//A类是Student的子类,同时也实现了Dirver接口和Singer接口
class A extends Student implements Driver, Singer{
@Override
public void drive() {} @Override public void sing() { }
}
public class Test {
public static void main(String[] args) {
//想唱歌的时候,A类对象就表现为Singer类型
Singer s = new A();
s.sing();//想开车的时候,A类对象就表现为Driver类型 Driver d = new A(); d.drive(); }
}
解释:
- 这里使用接口Driver指向实现类对象,后期可以随时修改实现类,达到接口的一个多态形式
2.9.2总结
1、使用接口有啥好处,第一个好处是什么?
- 可以解决类单继承的问题,通过接口,我们可以让一个类有一个亲爹的同时,还可以找多个干爹去扩展自己的功能。
2、为什么我们要通过接口,也就是去找干爹,来扩展自己的功能呢?
- 因为通过接口去找干警,别人通过你implements的接口,就可以显性的知道你是谁,从而也就可以放心的把你当作谁来用了(这样就可以通过implement中的接口方法,知道这个类的一些应该有的功能,必须存在这个功能)
3、使用接口的第二个好处是什么?
-
一个类我们说可以实现多个接口,同样,一个接口也可以被多个类实现的。这样做的好处是我们的程序就可以面向接口编程了,这样我们程序员就可以很方便的灵活切换各种业务实现了
Driver d = new A();
d.drive();
这里使用接口Driver指向实现类对象,后期可以随时修改实现类,达到接口的一个多态形式
2.10 内部类
- 是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
2.10.1.成员内部类是什么? 如何创建其对象?
- 就是类中的一个普通成员,类似前面我们学过的普通成员变量、成员方法
- 创建办法:外部类名.内部类名 对象名 =new 外部类(...).new 内部类(...);(根据外部类的实例对象创建)
2.10.2.成员内部类的实例方法中,访问其他成员有啥特点?
- 可以直接访问外部类的实例成员、静态成员(相当于类的一个方法,能直接调用类中的实例变量和静态变量)
- 可以拿到当前外部类对象,格式是: 外部类名.this.
2.12匿名内部类
功能: 实际开发中用得最多的一种内部类
-
就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字
-
特点: 匿名内部类本质就是一个子类,并会立即创建出一个子类对象
-
作用:用于更方便的创建一个子类对象
下面就是匿名内部类的格式:new 父类/接口(参数值){
@Override
重写父类/接口的方法;
}
下面是具体实现代码:
public interface Swimming{
public void swim();
}
public class Test{
public static void main(String[] args){
Swimming s1 = new Swimming(){
public void swim(){
System.out.println("狗刨飞快");
}
};
go(s1);
Swimming s1 = new Swimming(){
public void swim(){
System.out.println("猴子游泳也还行");
}
};
go(s1);
}
//形参是Swimming接口,实参可以接收任意Swimming接口的实现类对象
public static void go(Swimming s){
System.out.println("开始~~~~~~~~");
s.swim();
System.out.println("结束~~~~~~~~");
}
}
可以发现我们把匿名内部类创建的类对象作为方法传入到方法中,减少了一个类的创建,简化开发人员的工作。