面向对象
1,面对对象与面对过程的区别
什么是封装?我看到过这样一个例子:
我要用洗衣机洗衣服,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内 部的结构吗?有必要碰电动机吗?有必要了解如何通电的吗?
如果是对于面向过程来说,这些你都得知道。“吾生也有涯,而知也无涯”,面向对象的封装与庄子的思想遥相呼应:用有限的时间去做更多的事情。
面对过程是软件开发的先驱者,但其局限性不能满足当今的主流市场需求。
-
面对过程注重微观,每一步都亲力亲为;面对对象注重宏观,更加偏向于整体的流程。
-
性能:面对过程执行效率更高。Java是编译成字节码给JVM运行,而面向过程直接编译成机器码执行
-
复用性:面对对象的封装,继承极大的扩展了代码的复用性
2,面对对象特性
2.1,封装
【隐藏实现,暴露接口】
-
解耦
-
通过访问修饰符保证数据安全
-
访问权限修饰符
修饰符 | 权限范围 |
---|---|
public | 本类,子类,本包,外部包 |
protected | 本类,子类,本包 |
default | 本类,子类 |
private | 本类 |
2.2,继承
【实现代码复用】
但同时增强了类之间的耦合。子类可以继承父类非私有的属性和方法,并且可以扩展自己的属性和方法。
构造器的继承问题
- 构造器是不会被子类继承的,但子类的对象在初始化时会默认调用父类的无参构造器。
- 当父类显示写了有参构造器,且没有无参构造器。子类继承父类的时候必须显示的调用父类的有参构造器。调用的方式可以使用super(a,b)来调用。
子类,父类初始化过程
原则:静态优于非静态,父类优于子类
-
父类静态变量,静态语句块
-
子类静态变量,静态语句块
-
父类非静态代码块,构造器
-
子类非静态代码块,构造器
class Base {
// 1.父类静态代码块
static {
System.out.println("Base static block!");
}
// 3.父类非静态代码块
{
System.out.println("Base block");
}
// 4.父类构造器
public Base() {
System.out.println("Base constructor!");
}
}
public class Derived extends Base {
// 2.子类静态代码块
static{
System.out.println("Derived static block!");
}
// 5.子类非静态代码块
{
System.out.println("Derived block!");
}
// 6.子类构造器
public Derived() {
System.out.println("Derived constructor!");
}
public static void main(String[] args) {
new Derived();
}
}
执行顺序
Base static block!
Derived static block!
Base block
Base constructor!
Derived block!
Derived constructor!
2.3,多态
主要体现在方法重载和方法重写上。
方法重载指同一个类中方法名相同,参数类型,个数不同;
方法重写指子类重写父类,要求方法,参数列表相同,父类用private或者final修饰的方法不能重写。
【作用】
提高了代码的通用性。
关于向上转型
在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
关于强制转换
从子类到父类的类型转换可以自动进行
从父类到子类的类型转换必须通过造型(强制类型转换)实现
无继承关系的引用类型间的转换是非法的
2.3,继承之父——Object类
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类,则默认父类 为java.lang.Object类(任何类都可以调用Object的方法)
【Object的主要组成】
- public native int hashCode(); 取得hash码
- equals(Object obj) 比较对象
- clone() 可用于复杂对象的深拷贝
==与equals的区别
== 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型 就是比较内存地址。
equals,通常会被重写,比较引用类型的内容是否相同
但是很多类默认重写了:(比如String)
package java.lang;
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
3,关键字
3.1,static关键字
static可以修饰方法,变量,代码块,类,前两种应用更加常见。
static修饰方法
static修饰的方法称为静态方法,也称类方法,可以直接通过类名.方法名直接访问,不需要实例化对象访问。
- 非static方法可以访问static方法.
- static方法不能访问非static方法
static修饰变量
static修饰的变量称为静态变量,也称类变量,全局变量,可以直接通过类名.变量名直接访问,不需要实例化对象访问。
静态变量和实例变量的区别?
- 静态变量前要加 static 关键字,而实例变量前则不加。
- 实例变量属于实例对象,只有实例化对象后才能使用
- 静态变量属于类,也称类变量。可以直接通过类名引用。
static修饰符的继承问题
子类是不会继承父类被static修饰的方法和变量,但是可以调用。
static修饰代码块
代码块的作用:对类或对象进行初始化。
静态代码块【static修饰】
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次
非静态代码块
- 除了调用非静态的结构外,还可以调用静态的变量或方法。
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
3.2,final关键字
final关键字可以修饰类,方法,变量。
final修饰类
不能被继承
final修饰方法
方法不能被子类重写
final修饰变量
修饰基本数据类型的变量,想当于定义了一个常量。
修饰引用类型的变量,固定栈,不固定堆,也就是引用变量的地址是不可变的,但是引用地址指向的堆中的内容是可变的。
final, finally, finalize 的区别。
- final 用于声明属性,方法和类,分别表示属性不可变,方法不可重写,类不可继承。
- finally 是异常处理语句结构的一部分,表示总是执行
- finalize 是 Object 类的一个方法,用于回收对象
3.3,super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
4,interface与抽象类
4.1,interface定义
- 使用interface声明
- 包含常量,抽象方法
- 接口中的所有变量都默认是由public static final修饰的(不可更改)
- 接口中的所有抽象方法都默认是由public abstract修饰的(不可更改)
- 接口中没有构造器
- 接口采用多继承机制
4.2,抽象类定义
- 使用abstract声明
- 包含构造方法,抽象方法,普通方法,常量,变量
- 采用单继承机制
- 虽然是类,但是不能实例化
- 抽象类可以没有抽象方法,但有抽象方法的类一定是抽象类
4.3,抽象类和接口的相关问题
接口和抽象类的区别
- 声明方式的区别:interface和abstract
- 继承机制区别:单继承和多继承
- 包含的内容不同:
- interface只包含常量和抽象方法,常量默认用public static final修饰,抽象方法默认使用public abstract修饰
- abstract包含类的组成部分:构造器,方法,变量,常量。可以定义抽象方法(or not)
同时实现接口,继承类的声明顺序
先写extends,后写implements
class SubClass extends SuperClass implements InterfaceA{ }
普通类和抽象类有哪些区别
- (是否可以包含抽象方法)抽象类可以包含抽象方法
- (是否可以实例化)普通类可以实例化对象
抽象类可以用final修饰吗?
不能,抽象类的存在是让其他类继承的。使用final修饰就无法继承。
5,内部类
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者 称为外部类。
Inner class的名字不能与包含它的外部类类名相同;
内部类分为四种,分别是成员内部类,局部内部类,匿名内部类和静态内部类。
5.1,【成员内部类】
- 内部类可以无限制的访问外围类的所有成员属性和方法,包括private修饰
- 但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问
- 成员内部类中不能存在
static
方法, 但是可以存在static
域, 前提是需要使用final
关键字进行修饰.
public class OuterClass {
private String str;
public void outerDisplay(){
System.out.println("outerClass...");
}
public class InnerClass{
public void innerDisplay(){
str = "chenssy..."; //使用外围内的属性
System.out.println(str);
outerDisplay(); //使用外围内的方法
}
}
// 推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
--------------------
chenssy...
outerClass...
5.2,【局部内部类】(在方法或者作用域里的类)
只能在声明它的方法或代码块中使用
//定义在方法里:
public class Parcel5 {
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}
//定义在作用域内:
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
5.3,匿名内部类
一个匿名内部类一定是在new的后面,并且必须继承一个父类或实现一个接口。
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
5.4, 【静态内部类】
使用 static 修饰的内部类称之为静态内部类
它不能使用任何外部类的非 static 成员变量和方法。
public class OuterClass {
private String sex;
public static String name = "chenssy";
// 静态内部类
static class InnerClass1{
// 在静态内部类中可以存在静态成员
public static String _name1 = "chenssy_static";
public void display(){
// 静态内部类只能访问外围类的静态成员变量和方法
// 不能访问外围类的非静态成员变量和方法
System.out.println("OutClass name :" + name);
}
}
// 非静态内部类
class InnerClass2{
// 非静态内部类中不能存在静态成员
public String _name2 = "chenssy_inner";
// 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的
public void display(){
System.out.println("OuterClass name:" + name);
}
}
// 外围类方法
public void display(){
// 外围类访问静态内部类:内部类
System.out.println(InnerClass1._name1);
// 静态内部类 可以直接创建实例不需要依赖于外围类
new InnerClass1().display();
// 非静态内部的创建需要依赖于外围类
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
// 方位非静态内部类的成员需要使用非静态内部类的实例
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
----------------
Output:
chenssy_static
OutClass name :chenssy
chenssy_inner
OuterClass name:chenssy
6.异常处理
异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。
(开发过程中的语法错误和逻辑错误不是异常)
Java程序在执行过程中所发生的异常事件可分为两类:
- Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源 耗尽等严重情况。一般不编写针对性 的代码进行处理。
- Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使 用针对性的代码进行处理。
异常处理机制一: try-catch-finally
在编写程序时,经常要在可能出现错误的地方加上检测的代码, 如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据 而是字符等。过多的if-else分支会导致程序的代码加长、臃肿, 可读性差。因此采用异常处理机制。
-
Java程序的执行过程中如出现异常,会生成一个异常类对象, 该异常对象将被提交给Java运行时系统,这个过程称为抛出 (throw)异常。
-
如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处 理。如果异常没有在调用者方法中处理,它继续被抛给这个调用 方法的上层方法。这个过程将一直继续下去,直到异常被处理。 这一过程称为捕(catch)异常。
-
程序员通常只能处理Exception,而对Error无能为力。
-
异常处理是通过try-catch-finally语句实现的。
try{
...... //可能产生异常的代码
}
catch( ExceptionName1 e ){
...... //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
...... //当产生ExceptionName2型异常时的处置措施
}
[ finally{
...... //无论是否发生异常,都无条件执行的语句
} ]
-
如果抛出的异常是IOException等类型的非运行时异常,则必须捕获,否则 编译错误。也就是说,我们必须处理编译时异常,将异常进行捕捉,转化为 运行时异常。
异常处理机制二: throws
- 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这 种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理, 而由该方法的调用者负责处理。
- 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可 以是方法中产生的异常类型,也可以是它的父类。
- 重写方法不能抛出比被重写方法范围更大的异常类型。