首页 > 代码库 > 2、面向对象

2、面向对象

三大特性:

1、多态:方法的重载(同一类中方法名相同,参数列表不同)、重写/覆盖(父子中,方法名、形参列表相同,子类返回值类型比父类返回值类型相等或者更小,子类的访问权限应              比父类的更大或相等)

2、继承:extends,代码复用

3、封装:隐藏类的内部属性和实现,对外提供公共访问方式,外界通过setter、getter(setAbc对应abc)方法访问。

 

匿名对象:调用一次的时候使用

new Person().eat();

 

构造方法:初始化对象的时候调用,没有系统会提供,不需要返回值,不能使用static修饰 。

初始化代码块:先于构造方法执行,对象一建立就会调用,将所有构造方法中的公共信息进行抽取,给所有对象进行统一初始化

静态代码块>初始化代码块>构造函数

 

在系统开始执行构造器的执行体之前,系统已经创建了一个对象,这个对象还不能被外界访问,只能在该构造器中通过this来引用,当构造器的执行体执行结束后,这个对象作为构造器的返回值被返回,通常还会赋值给另一个引用类型的变量,从而让外部能够访问到  

子类不会获得父类的构造器,在子类中调用父类的构造器用super,必须出现在第一行,父类构造器总会在子类构造器之前执行
子类构造器调用父类构造器的三种情况:
1、第一行super显式调用  super(a, b)
2、this调用本类中重载的构造器,还是会调用父类的构造器
3、隐式调用父类的无参构造器

局部变量必须显式初始化,成员变量无需显式初始化

 

Person p = new Person();

创建一个对象都在内存中做了什么事情?

1先将硬盘上指定位置的Person.class文件加载进内存。

2执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量p。

3在堆内存中开辟一个实体空间,分配了一个内存首地址值。

4在该实体空间中进行属性的空间分配,并进行了默认初始化。

5对空间中的属性进行显示初始化。

6进行实体的构造代码块初始化。

7调用该实体对应的构造函数,进行构造函数初始化。()

8将首地址赋值给p ,p变量就引用了该实体。(指向了该对象)

 

this 谁调用代表谁

1、构造方法中引用正在初始化的对象

2、在方法中引用调用该方法的对象

最大作用:让类中的一个方法,访问该类中的另一个方法或者实例变量。

 

protected:同一包中的其他类或者不同包中的子类,通常希望子类来重写这个方法

default:相同包下的其他类

 

包package,类似命名空间
将一组功能相关的类放在同一个package下,从而形成逻辑上的类库单元
package 包名  // 第一个非注释放置
#import 导入包

 

java核心类都放在java包及其子包下,扩展类则放在javax包及子包下,这些类就是API

java.lang:核心类,String System Math Thread,系统自动导入。

java.util:工具类、集合类,Arrays和List Set。

java.text:格式化相关。

java.awt:抽象接口工具集,构建图形界面。

java.swing:Swing图形界面相关类,构建平台无关的GUI。

 

super用于限定对象调用从父类继承得到的实例对象和方法,不能用static修饰,this不能出现在static修饰的方法中

每一个子类构造内第一行都有默认的语句super();

 

多态

编译时类型和运行时类型不一致,相同类型的变量在调用同一方法时表现不同
编译时:类型由声明该变量时的使用的类型决定
运行时:由实际赋给该变量的对象决定

动态绑定技术:在执行期间判断引用对象的实际类型,根据其实际类型调用其相应的方法

static

1、为了实现对象之间重复属性的数据共享。

2、静态函数可以直接被类调用。

3、静态成员随着类的加载而加载,先于对象存在。

弊端:1、静态方法只能访问静态成员,不能访问非静态成员(静态方法加载时先于对象存在);2、静态方法中不能使用this、super关键字(this代表对象,静态方法加载时可能没有对象)。

静态变量(类变量),非静态变量(实例变量)。

静态变量可以被对象和类调用,而非静态变量只能被对象调用。

 

单例设计模式

 

1、因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该类对象;

 

2、就在类中创建一个本类的对象;

 

3、定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象

 

 1 // 饿汉式
 2 class Single {
 3     // 私有化构造函数。
 4     private Single() {
 5     } 
 6 
 7     private static Single s = new Single(); // 创建私有并静态的本类对象。
 8     // 定义公有并静态的方法,返回该对象。
 9     public static Single getInstance() { 
10         return s;
11     }
12 }
 1 //懒汉式:延迟加载方式。
 2 class Single2 {
 3     private Single2() {
 4 
 5     }
 6 
 7     private static Single2 s = null;
 8 
 9     public static Single2 getInstance() {
10 
11         if (s == null)
12 
13             s = new Single2();
14 
15         return s;
16 
17     }
18 }

 

不使用多继承:因为当一个类同时继承两个父类时,两个父类中有相同的功能,那么子类对象调用该功能时不知调用哪一个。

 

final特点:

1:这个关键字是一个修饰符,可以修饰类,方法,变量。

2:被final修饰的类是一个最终类,不可以被继承。

3:被final修饰的方法是一个最终方法,不可以被覆盖。

4:被final修饰的变量是一个常量,只能赋值一次。

 

抽象类abstruct
抽象类和抽象方法都用abstract修饰
1、抽象方法不能有方法体
2、抽象类不能被实例化,不能用new调用抽象类的构造器创建抽象类的实例,抽象类的构造器不能用于创建抽象类的实例,主要用于被子类调用
3、含有抽象方法的类只能被定义为抽象类    (1)直接定义了一个抽象方法  (2)继承了抽象父类却没有完全实现抽象父类包含的抽象方法  (3)实现了一个接口却没有完全实现包含的抽象方法
 
abstract修饰类时,该类只能被继承
abstract修饰方法时,该方法必须由子类实现(重写)
final和abstract不能同时用,final修饰的类不能被继承,final修饰的方法也不能被重写
abstract不能修饰成员变量,也不能修饰局部变量;不能用于修饰构造器
abstract不能同时修饰某个方法,即没有类抽象方法
abstract不能和final , private , static共存
 
接口interface
接口定义了多个类共同的公共行为规范,只规定类必须提供的方法,而不提供任何实现,规范和实现相分离
特殊的抽象类,全部都是抽象方法,不能包含普通方法
Java8允许在接口中定义默认方法,默认方法可以提供方法实现
 
修饰可以是public或者省略,省略默认相同包结构下才能访问
一个类可以有多个直接父接口
 
接口:成员变量只能是静态常量(系统会默认public static final,处于不同包下也可以通过接口来访问),方法只能是抽象实例方法(默认public  abstract,不能有方法体)、类方          法(必须有方法体,static) 和默认方法(default,必须有方法体,不能用static不能直接使用接口来调用默认方法),内部类(内部接口、枚举public static),都是public
类:初始化块,构造器,成员变量,方法,内部类
 

接口和抽象类的异同:

相同点:

1、都不能被实例化,用于被其他类实现或者继承
2、都可以包含抽象方法,实现或者继承时必须实现抽象方法
不同点:
1、两者设计目的不同:接口作为系统与外界交互的窗口,制定各个模块遵守的标准,体现一种规范(对于实现者而言规定实现者必须向外界提供某些方法;对于调用者而言可以调用哪些服务服务,如何调用);抽象类作为各个子类的共同父类,体现模板式设计,是系统实现过程中的中间产品,不是最终产品
2、接口里只能包含抽象方法和默认方法,不包含普通方法(抽象实例方法);抽象类可以包含普通方法
3、接口不能定义静态方法;抽象类可以定义静态方法
4、接口只能定义静态常量,不能定义普通成员变量;抽象类既可以定义普通成员变量,也可以定义静态常量
5、接口不包含构造器;抽象类可以包含构造器,不是用于创建对象,而是让其他子类调用构造器完成抽象类的初始化工作
6、接口不能包含初始化块;抽象类可以包含
7、一个类可以实现多个接口;一个类只能有一个直接父类

 

内部类
将一个类放在另一个类的内部定义
 
作用:
1、提供更好的封装,把内部类隐藏在外部类之内,不允许同一个包内的其他类访问该类
2、内部类作为外部类的成员可以直接访问外部类的私有数据,但外部类不能访问内部类的实现细节
3、匿名内部类用于创建只需要使用一次的类
 
定义内部类和外部类的区别:
1、内部类可以多使用3个修饰符:private、protected、static(外部类,省略控制符,同一包内;public)
2、非静态内部类不能拥有静态成员
 
非静态内部类
在非静态内部类对象里保存了一个它所寄生外部类对象的引用,当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,非静态内部类的实例必须寄生在外部类实例中
技术分享
非静态内部类的方法访问同名变量的优先级:
方法内的局部变量 > 内部类的成员变量 > 外部类的成员变量
它们之间用this 和外部类名.this来区分
 
非静态内部类可以直接访问外部类的成员;外部类想要访问非静态内部类成员,必须显式创建非静态内部类对象来调用访问其实例成员(在外部类对象创建,调用外部类对象的方法访问非静态内部类时,很可能非静态内部类对象并不存在)
 
不允许在外部类的静态成员中直接使用非静态内部类
 
不允许在非静态内部类中定义静态成员

 

静态内部类
static修饰,属于外部类本身
可以包含静态成员,也可以包含非静态成员
即使内部类的实例方法也不能访问外部类的实例成员(静态内部类对象是寄生在外部类的类本身中,而不是在外部类的实例中,当内部类对象存在时,不一定存在被它寄生的外部类对象)
外部类不能直接访问静态内部类的成员,但可以使用内部类名或者内部类对象来访问
 
可以在接口中只能定义静态内部类,用public  static修饰,默认访问权限为public
 
使用内部类:
1、在外部类内使用内部类
不要再外部类的静态成员(静态方法和初始化块)中使用非静态内部类,因为静态成员不能访问非静态成员
 
2、在外部类以外使用非静态内部类
在外部类以外的地方定义内部类   OuterClass.InterClass   变量名;
在外部类以外的地方创建非静态内部类实例     外部类对象.new  内部类构造器,非静态内部类的构造器必须通过其外部类对象来调用
 
创建一个子类时,子类构造器总会调用父类的构造器,在创建非静态内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象。
非静态内部类In对象和SubClass对象都持有指向Outer对象的引用,当创建非静态内部类In类的对象时,必须通过Outer对象来调用new关键字(Out.In in = new Out( ).new In("创建信息"));创建SubClass类的对象时,必须使用Outer对象作为调用者来调用In类的构造器(out.super("hello"))
非静态内部类的子类实例需要有一个指向其父类所在外部类对象的引用,即如果有一个内部类的子类对象存在,则一定存在与之对应的外部类对象
 
3、在外部类以外使用静态内部类
创建 new OuterClass.Inter.内部类构造器;
静态内部类的子类
public class 静态内部类的子类  extends StaticOut.Static
{
}
静态内部类比非静态内部类简单得多,要使用内部类时优先考虑静态内部类
 
内部类把外部类的类名当作一个命名空间,子类中的内部类和父类中的内部类就算完全同名也不能重写
 
局部内部类(很少用到)
放在方法中定义
不能用访问控制符(作用域是所在方法,其他成员不会访问方法中的局部变量)
不能用static(上一级是方法,而不是类,用static修饰无意义)
 
匿名内部类
只需要使用一次的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用
new 实现接口/父类构造器(实参列表)
{
}
 
匿名内部类不能定义为抽象类
匿名内部类不能定义构造器(由于没有类名,但可以通过定义初始化块来完成构造器的工作)
 
局部变量被匿名内部类访问,该变量自动加final,即赋值后不能重新被赋值
 
最常用的创建匿名内部类的方式是需要创建某个类型接口的对象

 

Lambda表达式
主要作用就是使用简洁的语法来创建函数式编程的实例,代替匿名内部类的繁琐语法
支持将代码块作为方法参数,允许使用更简洁的代码来创建只有一个抽象方法的接口(函数式接口)
Lambda表达式可以被当作任意类型的对象
 
Lambda表达式的类型称为“目标类型”,必须是函数式接口,只包含一个抽象方法,可以包含别的默认方法和类方法
如果采用匿名内部类创建函数式编程接口的实例,只需要实现一个抽象方法,这种情况下可采用Lambda表达式来创建对象
@FunctionalInterface注释放在接口前面,检查该接口必须是函数式接口,否则报错
@FunctionalInterface
interface FKTest
{
     void run();
}
 
限制:
1、目标类型必须是明确的函数式接口
2、只能为函数式接口创建对象
 
为保证Lambda表达式的目标类型是明确的函数式接口,三种常见方式:
1、将Lambda表达式赋值给函数式接口类型的变量
2、将Lambda表达式作为函数式接口类型的参数传给某个方法
3、使用函数式接口对将Lambda表达式表达式进行强制类型转换(将Lambda表达式的目标类型完全可能是变化的,唯一的要求是将Lambda表达式实现的匿名方法与目标类型即函数式接口中唯一的抽象方法有相同的形参列表)

 

Lambda表达式由三部分组成
1、形参列表,允许省略形参类型,要是只有一个参数,连形参列表的圆括号都可以省略
2、->
3、代码块,要是只包含一条语句可以省略花括号,要是只有一条return语句,都可以省略return关键字
 
Lambda表达式的代码块中只有一条代码,还可以在代码块中使用方法引用和构造器引用,让代码块更简洁

 

Lambda表达式和匿名内部类的联系和区别:

相同点:

1、都可以直接访问final类型局部变量,以及外部类的成员变量
2、创建的对象都可以从接口中继承默认的方法

区别:

1、匿名内部类可以为任意接口创建实例,不管有多少抽象方法只要所有的抽象方法实现即可,也可以为抽象类甚至普通类创建实例;Lambda表达式只能为函数式接口创建实例
2、匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式中不允许

 

枚举类enum
实例有限且固定
一个java源文件最多只能定义一个public访问权限的枚举类,且该源文件必须和枚举类名相同
 
枚举类和普通类的区别:
1、默认继承java.lang.Enum,而不是默认继承Object类,不能显式继承其他父类
2、使用enum定义、非抽象的枚举类默认用final修饰,不能派生子类
3、构造器只能有private访问控制符,默认或者省略都是
4、枚举类的所有实例必须在第一行显式列出,否则枚举类永远不会产生实例,系统自动添加public static final修饰

枚举类默认提供values()方法遍历所有枚举值

 

对象与垃圾回收
垃圾回收的特征:
1、只负责回收内存中的对象,不会回收任何物理资源(数据库链接、网络IO等)
2、当对象永久性失去引用时,系统会在合适的时候回收内存,无法精确控制
3、在回收任何对象之前,总会调用它的finalize()方法,可能使该对象重新复活(让一个引用变量重新引用该对象),从而导致取消回收
 
对象在内存中的状态:
1、可达:当对象被创建后有一个以上的引用变量引用
2、可恢复:对象不再有变量引用,准备回收该对象,系统调用finalize()进行资源清理,如果重新有变量引用该对象就变成可达;如果没有就变成不可达
3、不可达:对象不再有变量引用,且finalize()也没有对象引用,内存会被回收
 
通知系统进行强制垃圾回收,系统会接受建议有选择性的进行垃圾回收
强制垃圾回收步骤:
1、调用System类的gc()静态方法:System.gc();   // 通知系统进行垃圾回收
2、调用Runtime对象的gc()实例方法:Runtime.getRuntime().gc();
finalize()
定义在Object类中的实例方法,原型
protected void finalize() throws Throwable;
 
有4个特点:
1、永远不要主动调用某个类的finalize()方法,应该交由垃圾回收机制调用
2、何时以及是否被调用不确定
3、JVM执行可恢复对象的finalize()方法时可能使对象重新编程可达状态
4、JVM执行finalize()方法出现异常时不会报告异常,继续执行
 
 
对象的软、弱和虚引用
便于垃圾回收器随意释放对象
java.lang.ref包下面提供了3个类:SoftReference、WeakReference、PhantomReference
都提供一个get()方法用于获取被他们引用的对象
使用这些引用时,不能保留对对象的强引用,否则没有作用
 
1、SoftReference
内存空间不足时会被回收,常用于内存敏感的程序中
 
2、WeakReference
弱引用的级别比软引用更低,当失去引用且垃圾回收机制运行时会被回收
 
3、PhantomReference
对象只有一个虚引用时,类似于没有引用,主要用于跟踪被垃圾回收的状态,不能单独使用,必须和引用队列ReferenceQueue一起使用,程序可以通过检查与虚引用关联的引用队列是否包含了该引用,从而了解虚引用所引用的对象是否即将被回收
 
引用队列由java.lang.ref.ReferenceQueue类表示,用于保存被回收后对象的引用
 
由于垃圾回收的不确定性,当程序希望从软、弱引用中取出引用对象时,可能这个引用对象已经被释放了,要使用那个被引用的对象则需要重新创建对象

 

使用JAR文件
Java Archive File,Java文档文件,是一种压缩文件,称为JAR包,与ZIP兼容,区别在于JAR文件中默认包含了名为META-INF/MAINFEST
开发了一个应用程序包含了很多类,将这些类文件打包成一个JAR文件提供给别人使用,只要在CLASSPATH环境变量中添加JAR文件,JVM就可以自动在内存中解压JAR包,
把该文件当做一个路径,在这个路径中查找需要的类或包对应的层次结构
JAR文件就是一个路径,通常由jar命令压缩而成,可以把一个或者多个路径全部压缩为JAR文件
 
JAR文件的好处:
1、安全(能够对JAR文件进行数字签名,只有识别签名的用户才能用)
2、加快下载速度(用Applet时,将存在的多个文件压缩成一个JAR包,建立一次HTTP连接就可以下载所有文件)
3、压缩(使文件变小,压缩机制和ZIP一样)
4、包装性(让JAR包里面的文件依赖于同一版本的类文件)
5、可移植性(JAR包作为内嵌在Java平台内部处理的标准,能够在各个平台上面使用)
 
 
异常
1 try {
2     需要被检测的代码;
3 }
4 catch(异常类 变量名) {
5     异常处理代码;
6 }
7 fianlly {
8     一定会执行的代码;
9 }

 

java异常体系

 |——Throwable  (实现类描述java的错误和异常)

      |——Error (错误)一般不通过代码去处理。

      |——Exceprion (异常)

            |——RuntimeException (运行时异常)

            |——非运行时异常

2、面向对象