final object abstract 接口 多态 内部类
final 是一个关键字,是最后的,最终的,被修饰的内容不能改变
可以修饰的内容:
1. 类:final修饰的类不能有子类.
2. 成员变量:变量是一个终值,不能再被改变.所以在定义时必须先手动给一个值.
3. 局部变量:被final修饰的局部变量是一个终值,不能再被改变.
4. 方法:final修饰的方法不允许重写
- final修饰变量的时候必须初始化
空白final,数据类型是可以不赋初始值,可以在创建对象的调用构造方法的时候,赋初始值
如果final成员变量 定义时不给值,但是在构造方法里必须给值
如果成员变量在定义时先不给值,但是必须在构造方法中给值,即必须保证属性是被初始化了的.这种情况叫空白final.
空白final:指被声明为final但又未给定初值的域.但是无论什么情况,编译器都确保空白final在使用前必须被初始化.
好处:空白final在final的使用上提供了更大的灵活性,因为一个类中的final域可以做到根据对象而有所不同,却又保持其恒定不变的特性.
public class BlankFinal {
private final int i = 0;
private final int j;
private final Poppet p;
public BlankFinal() {
j = 1;
p = new Poppet();
}
public BlankFinal(int j) {
this.j = j;
p = new Poppet();
}
public static void main(String[] args) {
BlankFinal bf = new BlankFinal();
}
}
class Poppet {
}
- 什么情况下不能有子类?
1.类中功能已经很全了,String
抽象类 abstract
抽象类:在继承中,提取父类方法的时候,每个子类都有自己具体的方法实现,父类不能决定他们各自的实现方法所以父类干脆就不管了,在父类中只写方法的声明(负责制定一个规则),将方法的实现交给子类.在类中只有方法声明的方法叫抽象方法,拥有抽象方法的类叫抽象类。
**抽象类的功能:**1.可以节省代码 2.可以制定一批规则。
抽象类不一定有抽象方法,但是有抽象方法的一定时抽象类
抽象类不能创建对象,必须通过非抽象类的子类,创建对象
继承了抽象类的子类一定要实现抽象方法,如果不实现就只能将自己也变成抽象的.
抽象方法,就是确定你必须做这件事,但是你做这件事的方法,得你自己定。比如:老师让做一道题,学生做的方法可以一样但是必须的做。
- abstract与 final 和 private static 不可共用。
-
1.final:被final修饰的类不能有子类,方法不能重写,但是abstract必须有子类,必须重写
2.static:修饰的方法可以通过类名调用,abstract必须通过子类实现
3.private:修饰的方法不能重写,abstract必须重写
接口 interface 声明规则
接口也是抽象的
- 成员变量默认:public final static
- 成员方法默认:public abstract
为什么要可以实现多个接口?
让java间接实现多继承,
- 接口和接口之间时多继承。
1. 问题一:接口与父类可以同时存在吗? 可以
2. 问题二:父类与接口的功能如何分配? 一般父类中放的时主要功能,接口中放的是额外的功能,接口作为父类的补充。
3. 问题三:接口和接口之间的关系? 接口和接口之间可以多继承
接口中子类重写方法注意:
- 如果以个类实现了两个接口,者两个接口同时出现的抽象方法,在这个子类中,只需重写一次这个方法。
- 如果接口中有default修饰的方法是不需要重写的。
interface inter6{
public void run();
default public void eat(){ //default只能放在接口中
System.out.println(“default1”);
static public void bark(){
System.out.println(“static1”);
}
public void play();
}
class Test6 implements inter5{
//
public void run() {
System.out.println(“Test6”);
}
- 如果两个接口中方法名相同都是default方法,里面的方法体不同,在类中需要重写该方法。
- 如果两个接口中方法名,参数都相同的方法,一个接口是抽象方法,另一个是default修饰有方法体。这时该类也必须重写该方法。
- 子类的静态方法可以与父类的相同,但是方法在调用的时候各自调用各自的
-
static public void bark(){
System.out.println(“substatic”);
}
如果两个接口有同样的方法,可以用一个类来实现。
从JDK1.7,以后的接口,但是方法必须使用Static或者default修饰,因为接口的方法必须重写,麻烦。如果两个接口有同样的已经实现的方法,必须重写
面向接口编程,一个类一个接口,使用的时候调接口。
设计模式:前人总结的经验,一些常见问题的解决方法,后人直接拿来用
常用的设计模式23:单例,工厂,代理,适配器,装饰,模板,观察者等,每个单例都有一个对应的类
第一种:单例:一个类只允许有一个对象,建立一个全局的访问点,提供出去供大家使用。
- 类中手动重写构造,并且私有化
- 在类的里面 new一个对象(private final static ),在方法public里提供访问,必须是静态的(因为不需要对象调用)
-
为什么要final修饰引用,引用不可变
注意:在单例中一般只有向外提供s的方法是静态的,其他的都是非静态的
1. 形式 饿汉式
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static、final修饰
private static final Singleton instance = new Singleton();
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
return instance;
}
}
“饿汉模式”的优缺点:
优点:实现起来简单,没有多线程同步问题。
缺点:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
2. 形式 懒汉式
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static修饰
private static Singleton instance;
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
“懒汉模式”的优缺点:
优点:实现起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。
通过地址的长期保存,来保存对象
- 使用: 功能从局部变成全局的。对象也变成全局。
高内聚低耦合:模块之间的联系越少越好。
模块化编程:
单例的例子:runtime
多态:一种事物的多种形态
- 继承是多态的前提
- 方法重写
- 父类引用指向子类对象,直接父类和间接父类都行
程序运行的阶段:
预编译:程序打开的时候,活儿已经干完了.(预处理命令 #define)
编译:从打开程序开始到点击左上角的三角之前—只能识别=前面的引用类型,不会识=后面的对象
运行:从点击三角开始—真正的识别对象,对象开始干活儿
实现动态的手段:动态类型,动态绑定,动态加载
**动态加载:**我们在编译阶段不能确定具体的对象类型,只有到了运行阶段才能确定真正的干活儿的对象.
**运行多态(Person p = new Student();)的工作机制:**在编译的时候识别的是引用类型,不识别对象.所以只能识别出Person里面的方法,但是在运行的时候是右边的对象去执行操作的。
缺点:只能直接调用子类重写父类的方法,不能直接调用子类特有的功能。(是因为编译的时候,执行的左边,如果引用去调用子类特有的方法时,机器识别不了,会报错)
优点:提高代码的扩展性,Demo9
向上转型和向下转型
注意:在多态环境下,才有向下转型和向上转型
- 向上转型:相当与是自动类型转换,多态本身就是向上转型,
- 作用:实现多态
- 向下转型:相当与强制类型转换
- 作用:解决多态中无法调用子类特有属性的缺点。
instanceof:确定当前对象是否是后面类或子类的对象,返回true or false。因为多态所以不知道,运行时,父类代表谁的对象。
insranceof 前后必须有继承关系!
多态下成员变量的使用
- 编译的时候能不能访问看父类,运行时也看父类。
- 静态成员方法:编译时运行时都看父类。
Object 基类
- equals();
- hashCode();
- toString(); 打印对象的时候默认调用toString();通过重写toString可以输出对象的属性;
- getClass();得到当前对象的字节码文件。Class 类,
在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。Java使用Class对象执行其RTTI(运行时类型识别,Run-Time Type Identification),多态是基于RTTI实现的。
每一个类都有一个Class对象,每当编译一个新类就产生一个Class对象,基本类型 (boolean, byte, char, short, int, long, float, and double)有Class对象,数组有Class对象,就连关键字void也有Class对象(void.class)。Class对象对应着java.lang.Class类,如果说类是对象抽象和集合的话,那么Class类就是对类的抽象和集合。
Class类没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
- clone();
内部类:定义在一个类中的类,内部类的地位和外部类的成员变量,成员方法一样。内部类可以直接访问外部类 包括私有的,成员之间是可以相互调用的。
调用内部类的方式:第一种:借助于外部类的方式实现 第二种:直接在这里调用(外部类.内部类)
1.Outer.Inner in=Outer.new Inner(); //创建内部类的对象
2.import导包,直接创建
作用:可以间接实现多继承。
class A1{
}
class B1{
}
//说明功能
//我们可以通过内部类让java间接实现多继承
class X extends A1{
class Y extends B1{
}
}
局部内部类:定义在方法中的类,生存周期和方法一样。
作用:可以让功能私有化,在类中。对方法内部的代码进行整理,增强代码可读性
class Test11{
public void play() {
//我们通过局部内部类实现了功能的私有化,并对方法内部的代码进行了整理,增强了代码的可读性和可操作性.
//因为函数的定义不能嵌套,所以这里要通过局部内部类实现
// public void gongneng1(){
// System.out.println(“功能1”);
// }
// public void gongneng2(){
// System.out.println(“功能2”);
// }
class Inner{
public void gongneng1(){
System.out.println(“功能1”);
}
public void gongneng2(){
System.out.println(“功能2”);
}
}
Inner inner = new Inner();
inner.gongneng1();
inner.gongneng2();
}
public void run(){
//因为两个方法是play的局部内部类方法.play之外不可见
// gongneng1();
// gongneng2();
}
}
局部内部类所在的方法中局部变量的使用
- 局部变量的作用域:定义变量开始到函数结束
- final:被final修饰的变量会被放在常量区,而常量区的值存在的时间要大于局部变量的所在的方法,相当于从原来的基础上扩大了作用域,
- **原理:**当方法中同时存在局部内部类与成员变量时,成员变量的使用范围就会从原来的基础上进行扩大.
- 原因 ::在当前的情况下,程序会默认让final去修饰height.所以当局部变量所在的方法结束的时候,变量没有被释放,保存的值还在.
public class Demo15 {
public static void main(String[] args) {
Outer1 outer1 = new Outer1();
outer1.show();
}
}
class Outer1{
int age;
public void show() {
int height=8;
//局部内部类
class Inner{
public void eat() {
System.out.println(“eat”+height);
}
}
System.out.println(“show”);
Inner inner = new Inner();
inner.eat();
}
}
在jdk1.7之后,java的内部机制已经在变量的前面默认添加了final
静态内部类:不一定有静态方法,有静态方法必须有静态内部类。
Out.Inn in = new Out.Inn(); / /创建
class Out{
static int age;
//静态内部类不一定有静态方法,有静态方法的一定是静态内部类
static class Inn{//静态内部类
public void play() {
System.out.println(“play”);
}
public static void show() {
System.out.println(“show”);
}
}
}
匿名内部类:定义在类方法中的匿名子类对象。
创建匿名内部类对象注意点:1.匿名内部类对象必须有父类或者父接口
所有的匿名对象,除了Object匿名对象,都是匿名内部类
* 内部类的作用:
* 1.间接实现了多继承
* 2.方便定义
* 3.只有外部类可以访问创建的内部类的属性和方法,包括私有方法
* 4.同一个包中其他的类不可见,有了很好的封装性
- new Animal11().eat();//匿名对象
- new Dog11().eat(); //匿名子对象:使用已有的子类创建匿名子类对象
- 第二种方式:这里也是Animal的匿名子类对象
new Animal11() {
@Override
public void eat() {
// TODO Auto-generated method stub
super.eat();
}
public void show() {
}
}.show();
匿名内部类
//匿名内部类:
class Test1{
public void show() {
//匿名内部类
new Animal() {
@Override
public void eat() {
// TODO Auto-generated method stub
super.eat();
}
};
}
//普通的匿名对象作为参数
public void canShuTest() {
System.out.println(new Animal());
}
//匿名内部类作为参数
public void canShuTest1() {
System.out.println(
new Animal() {
public void eat() {
// TODO Auto-generated method stub
super.eat();
}
@Override
public String toString() {
return “haha”;
}
}
);
}
//普通的匿名对象作为返回值
public Animal fanHuiZhiTest() {
return new Animal();
}
//匿名内部类作为返回值
public Animal fanHuiZhiTest1() {
return new Animal() {
};
}
}