面向对象的思想是相对于面向过程而言的,两者都是解决问题的方式,但是它们的出发点不同。
面向过程的方式关注的是通过怎样的步骤解决问题,一般通过若干紧密联系的步骤达到解决问题的目的。面向对象的方式关注的是怎么样将问题尽量拆分为相互独立的任务,然后以不同的身份去解决这些任务,最后组合这些任务输入达到解决问题的目的。
这样看来面向过程的方式显得更直接一些,但是当遇到的问题规模和复杂程度很大时,这样的处理方式会使得解决的过程变得十分繁琐,思路不够清晰,并且当问题有所变化时,解决方案不好及时作出调整。面向对象的方式,首先将大的问题拆分为相关性很小的不同的子任务模块,这样就可以将这些子模块分配给不同的对象去解决,各个对象之间不需要知道对方内部的具体工作内容,只需要知道相互之间可以怎样交互就可以了,通过模块之间的相互调用协作完成最终的大问题,当问题需求出现变化时,很可能只需要调整各个模块之间的协作方式,就能做出及时的应对,而不需要从头来过。所以面向对象的思想更加适合真实世界中复杂问题场景的需求。
可以这样理解,面向过程是面向对象的基础环节,面向对象是面向过程的上层建筑。面向对象的解决思路中,一个个的子模块中的子问题的解决依然是面向过程的方式,它们通过一层层的包装实现了模块化的结构,就像是一个个提前生产好的工具包,这样可以减少不必要的重复工作,降低任务间的耦合程度,更加灵活地应对不同场景的需求。
大致的的顺序是静态资源先于非静态资源被加载。下面以Person
类为例进行叙述。
1. 静态初始化只会在首次需要用到时被初始化一次,这个被用到的时机是`Person`类对象被首次创建或者`Person`类中的静态资源(属性或方法)被首次访问。 2. 静态初始化之后是非静态初始化。当使用`new Person()`创建`Person`对象时(静态资源在这之前已经被加载),`Person`对象中的所有基本类型数据被设置为默认值(0或false或'\u0000'),引用被设置为`null`。之后执行出现在代码中的字段定义处初始化动作。然后执行构造器。
重载(Overload)是在一个类中,方法名相同,而参数列表不同。而返回类型不作为评判标准,即可以相同也可以不同。
重写(Override)是子类对父类的可继承方法的重新实现,其参数列表不能改变,即“换心不换壳”。而对于返回类型,在 Java 5 之前的重写必须保持返回类型不变,Java 5 之后引入了协变返回类型,即子类重写方法可以返回父类方法的返回类型的子类型。所以,如果父类方法的返回值类型是Object
,那么子类的重写方法就可以返回任意类型的值。
int
属于基本数据类型,基本数据类型的变量不需要使用new
来创建,而是直接使用一个变量类存储“值”,由于基本数据类型的使用频率很高,这样创建更加方便高效。Integer
是基本数据类型int
的包装类型,每个基本数据类型都有自己对应的包装类型,用于在堆内存里表示基本类型的数据。
Java 中char
类型变量使用Unicode
编码存储字符,因此可以存储中文汉字。
char c = '中';
两者都是用于对象的序列化,即保存内存中的对象到硬盘中,以供下次直接使用(反序列化)。对象需要序列化就必须使其类实现 Seriablizable 或者 Externalizable。两者的区别如下:
Transient
修饰类取消指定属性的序列化);而Externaliable
在我们不希望序列化那么多属性的情况下可以使用,它要求我们实现两个方法:writeExternal()
和readExternal()
来指定序列化和反序列化那些属性(此时Transient
关键字不再起作用)。抽象类是包含抽象方法的类。抽象类和抽象方法使用abstract
修饰。抽象方法是只有方法声明没有方法体的方法,如下:
abstract void func();
如果一个类包含一个或多个抽象方法,那么该类本身也必须定义为抽象的,否则编译不通过,如下:
abstract class Person { abstract void speak(); }
编译器不允许创建抽象类的对象,因此必须在继承并实现其所有抽象方法之后的子类中创建对象。抽象允许同时拥有任何非抽象方法的一般成员,且抽象类的抽象方法可以使用权限修饰符设置访问权限,但禁止被修饰为private
,因为这样的话该抽象方法就永远不能被实现。
接口是相对于抽象类更进一步的抽象。接口使用interface
关键字来创建,它的所有方法必须是抽象的,并且它们是默认以public abstract
修饰的,所以不需要在方法前添加任何修饰,并且也不能以任何其它方式修饰,它们只能是publid abstract
的,如下:
public interface Person { void speak(); int func(); }
接口通过使用implements
在新的类中实现它的所有抽象方法,之后才能被实例化,如下:
public class PersonImpl implements Person { public void speak() { System.out.println("你好!"); } public int func() { return 1; } }
Java 8 之前的接口只允许包含抽象方法,Java 8 之后的接口允许包含默认方法、静态方法以及属性。默认方法使用关键字default
修饰,这样就可以在接口中提供方法的实现,并且可以在实现类中调用它。接口中的属性被隐式地修饰为为static final
,且不能以其他方式修饰。
String
类是不可变的,String
类中每个看起来会修改本身值得方法,都会创建一个新的String
对象来存储修改后得字符串内容;StringBuilder
和StringBuffer
都是可变的。所以,当代码中涉及到频繁更改变换字符串的行为时,使用String
的速度比StringBuilder
要慢得多。String
不可变,因此是线程安全地,StringBuilder
是可变的,不是线程安全的。StringBuffer
虽然也是可变的,但它内部的很多方法可以带有 synchronized
关键字进行同步,所以可以保证线程安全。所以如果要进行的操作是多线程的,那么就要使用StringBuffer
,但在单线程运行的情况下,StringBuider
更快。final
是修饰符,用于修饰类、方法或者属性。final
修饰类时,它意味着该类不能被继承,因此不能使用final
修饰抽象类或接口。final
修饰方法时,意味着该方法不能被重写,只能被使用,因此同样地,不能使用final
修饰抽象方法。final
修饰属性或局部变量时,它只有一次被初始化地机会,且必须在其被使用之前,之后就不能对其进行任何改动,对于对象属性或变量来说,这意味着它不能再引用任何其它的对象,但对象本身的内部属性是可以更改的。finally
是关于异常处理中的关键字,在提供了执行清理操作的办法。不管有没有异常被捕获,即不管try
中代码块正常执行或者异常触发被抛出还是异常被捕获进而执行catch
代码块,finally
代码块中的内容都会被执行,即使try/catch
代码块中包含return
语句,finally
代码块同样会执行。finalize
是方法名。Java 中可以使用finalize()
方法在垃圾收集器将对象从内存中清楚出去之前做必要的清理工作。该方法是在Object
类中定义的,因此所有的类都继承了它。子类通过重写finalize()
方法以整理系统资源或者执行其它清理工作。它是由垃圾回收器,在确定该对象没有被引用,需要被删除之前调用的。Java 中以Throwable
类为任何可以作为异常类型的基类,进一步分为两种类型:Error
和Exception
。其中Error
用来表示 JVM 无法处理的错误,Exception
表示程序执行中的异常。Exception
也分为两种:受检异常(Checked Exception)和非受检异常(Unchecked Exception)。受检异常是从语法角度必须被处理的异常,如果不处理,程序就不能编译通过。不受检异常包含的是Exception
中的一大分支RuntimeException
(运行时异常),这些异常一般是由程序逻辑错误引起的,应该从逻辑角度尽可能地避免这类异常发生,可以选择捕获处理,也可以不处理。
Java 的异常处理实际上就是抛出异常和捕获异常。
所有的异常实际上都是以对象的形式存在的,我们也可以编写自定义的异常类型,并在合适的地方抛出自定义异常对象或者在并合适的地方编写处理程序。
Java中的String,StringBuilder,StringBuffer三者的区别
Java中final、finally和finalize的区别
Externalizable和Serializable
Java提高篇——Java 异常处理