如何理解面向对象
我们说面向对象具有三大特征:封装性、继承性和多态性,那么我们怎么去理解所谓的封装、继承、多态?
1、封装:功能都给你做好了,你不必去理解它是怎么写出来的,直接使用即可。
如:房子、电脑、手机、饮料等等都可以认为是一次封装,而他们怎么做出来的,你不需要关心。
2、继承:你从父辈那继承了家产,你身体流淌着父母的血液,这也就是所谓的继承,继承你也可以把它想象成基础的类。
我们说学一样东西一定要把基础打牢,那为什么需要把基础打牢呢?因为不管多么复杂的东西,都是从简单才到复杂的,也就是说它是根据基础演变而来。
说更简单一点,我们说猫啊,狗啊,老虎,虽然它们形态各异,但它们始终都有其共同点,吃喝拉撒睡,那不是人吗?人不也是动物嘛,既然它们这么相似,于是就有人把它们分到一个类中,也就是所谓的动物。
那么为什么需要分类呢?个人感觉,一切为了方便,就好像为什么要分男的和女的,你说你要找一个人,在这种不明确的情况下,肯定需要花费很多时间,但如果你说你要找女的,那么就可以减少一半的时间,虽然没有一半,但这肯定是减少了很多的时间,从另外一个角度来讲,可以和其他类做区分,比如,我们说要吃水果,那肯定就不是鱼啊,包子之类的。
所谓的基类就是,这一个类中所有成员的共性,比如:男人和女人,他们是不是有共同点,而这些共同点就可以把它抽象成“人”。所以当我们说人时,你既可以把它想象成是一个男人,也可以想象成是一个女人,所谓的多态就是从这演变出来的。
3、多态:同一类事物有多种形态,注意是同一类事物
刚刚还是晴空万里,瞬间倾盆大雨,这就是天空的多态。春天的树,新枝嫩叶,冬天的树叶都枯萎了,说明树具有多态性。
构造器
构造器也叫构造方法(constructor),用于对象的初始化。在我们初始化对象时,如果希望设置一些默认值,那么就可以使用构造器。
构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。
构造器的名称应与类的名称一致。
Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
class Test{ private String name; Test(String n){ name = n; } public String getName(){ return name; } } public class app { public static void main(String[] args){ Test test = new Test("小王"); String n = test.getName(); System.out.println(n); } } // 小王
并且可以发现这个构造器是在new的时候执行的。如果是继承至某个父类,那么我们可以在子类中调用super来手动执行父类中的构造器。
class Test{ private String name; Test(String n){ name = n; } public String getName(){ return name; } } class Test2 extends Test{ Test2(String n){ super(n); } } public class app { public static void main(String[] args){ Test2 test = new Test2("老王"); String n = test.getName(); System.out.println(n); } } // 老王
前面之所以说是手动是因为,就算你不去调用父类的构造器,它还是会被执行,只是它执行的是没有参数的构造器。我们不妨来看看下面这段代码
class Test{ Test(){ System.out.println("Test"); } } class Test2 extends Test{ Test2(){ System.out.println("Test2"); } } public class app { public static void main(String[] args){ Test2 test = new Test2(); } } // Test // Test2
程序自动调用了父类的构造器,而且还比子类构造器先执行,之所以父类的构造器先执行是有原因的,你想啊,子类往往需要用到父类中的一些变量或方法,如果不先初始化父类中的构造器,那么肯定就会出现一些问题。
要点:
1. 通过new关键字调用!!
2. 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
3. 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数。如果已定义则编译器不会自动添加!
4. 构造器的方法名必须和类名一致!
垃圾回收机制
我们知道一个方法,可以无数次的被调用,因此如果没有一个合理的规范,那么每次执行都会加大内存的消耗,而且有些方法执行完毕以后就没有任何意义了,因此一些语言中加入了垃圾回收,对于一些没有用处的进行回收,当然垃圾回收不仅仅针对方法。
但是话说回来你也不能乱回收对吧,得有一个规范,而这个规范就是,如果一个对象没有被引用,或被设置成null,又或者当前对象被其他对象所覆盖,那么它就会变成垃圾,会被垃圾收集器所回收。
内存管理
Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放。
对象空间的分配:使用new关键字创建对象即可
对象空间的释放:将对象赋值null即可。垃圾回收器将负责回收所有”不可达”对象的内存空间。
垃圾回收过程
任何一种垃圾回收算法一般要做两件基本事情:
1. 发现无用的对象
2. 回收无用对象占用的内存空间。
垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用该对象。Java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。
垃圾回收相关算法
1. 引用计数法
2. 引用可达法(根搜索算法)
方法的重载(overload)
方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。
class Test{ public void a(){ System.out.println("正常"); } public void a(String t){ System.out.println("第二个a" + t); } } class app{ public static void main(String[] args){ Test test = new Test(); test.a("啊"); // 函数被重载 test.a(); // 未被重载 } } ------Output------ 第二个a啊 正常
重载的方法,实际是完全不同的方法,只是名称相同而已!
构成方法重载的条件:
1.不同的含义:形参类型、形参个数、形参顺序不同。
2.只有返回值不同不构成方法的重载。如下:不构成方法重载
int a(String str){}与 void a(String str){}
3.只有形参的名称不同,不构成方法的重载。如下:不构成方法重载
int a(String str){}与int a(String s){}
方法的重写
通俗讲就是覆盖,在Java好像对同一个类中,不支持重写,下面这段代码,运行就报错了。
class Test{ public void a(){ System.out.println(0); } public void a(){ System.out.println(1); } } class app{ public static void main(String[] args){ Test test = new Test(); test.a(); } } ------Output------ app.java:5: ??: ??? Test?????? a() public void a(){ ^ 1 ???
一般来说,也没人会这么写,使用重写,基本上是在继承中,比如下面这段代码。
class Test{ public void a(){ System.out.println(0); } } class Test2 extends Test{ public void a(){ System.out.println(1); } } class app{ public static void main(String[] args){ Test2 test = new Test2(); test.a(); } } ------Output------ 1
Test2重写了Test中的a方法,不过在Java中,如果你想要重写某个方法,需要遵守几个规则,重写的函数返回类型需要和父类中返回的类型相同,形参相同,访问权限不能比父类中的小,比如下面这个就有问题
class Test{ public int a(){ return 0; } } class Test2 extends Test{ private int a(){ return 1; } } class app{ public static void main(String[] args){ Test2 test = new Test2(); test.a(); } } 报错
这段代码之所以报错是因为,Test2的方法a比父类的a权限小,但反过是可以的。