您的位置:首页 > 编程语言 > Java开发

java面向对象思想笔记

2016-05-21 18:56 288 查看
面向对象与面向过程的区别:

我要去新疆

面向过程:

我要开车,我挂档,我踩油门,我过河北,我过陕西.......

一切以我为中心,一切以我为主语

面向对象:

我命令车去新疆

车怎么过去不关我的事情

->信息封装在车这个类的内部

->我不用去了解车整个开动的过程

面向对象的思维方式:

在面对问题的时候,不应该再去想,

第一步该干什么

第二步......

第三步......

....................

而应该这样想:

我应该把谁给抽象出来,实现这个事情

需要哪些的类,这些类应该具有什么样

的属性和方法,以及这些类和类之间所

具有的关系是什么.

面向对象的基本思想是:

从现实世界中客观存在的事物出发来构造软件系统

并在系统的构造中尽可能的运用人类的自然思维模式

它更加的强调运用人类在日常的思维逻辑中经常采用的

思想方法与原则,如抽象,分类,继承,聚合,多态等.

面向对象的基本概念

对象:计算机语言对问题域中事物的描述,对象通过"属

性"和"方法"来分别对应事物所具有的静态属性 和 动

态属性.

类:用于描述同一类型的对象的抽象概念,类中定义了这

一类对象应该具有的静态和动态属性.

类可以看成是一类对象的模板,而对象可以看成是类的

一个具体的实例.

合适方法出现在合适的类里面

类和类之间的关系:

最弱的就是关联,关联就是一个类的某

个方法中的参数是另一类.

分辨继承关系:

继承关系的最简单的一句话就是:

XX是一种XX

比如:老师是一种人

意思就是老师是从人继承而来的

聚合关系:聚集和组合

指的是整体和部分之间的关系,

比如:

球队 : 由教练和队员组成

人: 由头,胳膊,腿......组成

分辨聚合关系:

XX是XX的一部分

如果这句话可以说通,那么它们之间就是

聚合关系

比如:队员是球队的一部分

脑袋是人体的一部分

不同的聚合关系有一定得差别,比如球队

中,组成球队的元素与球队的关系就没有

组成人的各部分与人之间的关系那么的紧密

所以球队与教练和队员之间是聚合

而人体的各部分和人的关系式组合

类和类之间的关系,弱的关系有关联,强的关系

有:继承,聚合,实现

在封装的时候,跟业务逻辑没有关系的不用去封装它.

java里面,万事万物皆对象

java里面成员变量和局部变量的重要区别就是,如果

成员变量没有被初始化,那么系统就会给它赋予初值

而局部变量则不是如此,你要自己给它进行初始化.

内存的分配:

四个区域:

1.栈区 存放的正在运行的代码中的参数及基本类型变量

先进后出

2.堆区 存放的是运行中生成的将要调用的参数

3.data segment 数据区 存放的是静态的变量和常量(

包括字符串常量和static变量)

4.code segment 代码区存放运行的代码

基础类型是只有一个名字和一块存储数据的区域

组成的一块内存,它只占用一块内存

引用类型占用两块内存:一个是对它的引用,或者

说是它的名字,另一个是存储它具体内容的大的

内存. 其实引用就是指向具体内容的一个指针.

小的内存指的是栈内存,而大的内存指的是堆内

存.

引用:一小块内存,指向一大块内存.不过这个小块

的内存指向的不是大内存的物理地址,但是它可以

找到那块大的内存.

为什么把对象放入堆内存呢?

因为在程序运行之前无法预知对象的具体大小,所

无法准确的分配它的大小,因此需要对它的内存进

行动态的分配,而堆内存正好是进行动态分配内存

来用的,它比较大,所以就把new出来的对象放入了

堆内存

而类是放在代码区的也就是code segment里面

类的方法只有在执行的时候才会占用内存,否则它

就不会占用内存的.

实例化过程

在实例化一个对象的时候,要调用构造方法,如果构

造方法中有要传入进去的值的话,那么栈内存就会

为这些值分配空间,否则没办法实例化,在实例化完

成之后这些在实例化过程为传入的值所分配的空间

就会回收,就消失了,把空间让给其他的方法去使用.

而通过那个指针内存就可以找到那个实例化的堆内

存.

任何的局部变量都会分配在栈内存中,只不过在方法

执行过后,方法的局部变量就没了消失了.这个也正好

可以很好的解释为什么java是安值传递的,方法不能

改变基本类型变量的值如下程序,值传递的过程是

copy的过程

public static void main(String[] args) {

int i=10;

new DiGui().changeCode(i);

System.out.println(i);

}

public void changeCode(int j){

j=100;

}

在main()方法调用完了changeCode(int j)它之后

为这个方法所分配的空间就会消失,不复存在,也就是

根本就不存在j=100;这个空间了,更不会打印出来100

了,而i是基本类型的数据,它的值依然存在依然是9因为

main()方法还没有结束,如果main()方法结束了,那么i

也会消失的.

类名首字母大写,方法,变量名首字母小写,运用驼峰

标识,就是furColorCode这种类型的.

垃圾回收的时机:没有任何的引用指向它的时候就会

调用垃圾回收机制.

在main()方法中调用函数的过程中,函数里面的参数会

在栈里面生成一个指向堆内存的小块内存,在这个方法

调用完毕后,这块在栈中小块内存就会自动消失,然后堆

内存的那块内存就会被垃圾回收机制给回收掉.

同样的,在main()方法结束的时候,为main()方法中分配

的内存也会消失,比如new一个新的对象,它会在main()

方法结束时消失掉,而与之相对应的堆内存里面的内容

也会被垃圾回收机制所回收.

内存分配总结:

方法执行,内存就开始被相应的分配

方法结束,内存就会被相应的收回

不论是main()方法还是普通的方法都是一样的

对于基本类型的参数只分配一块内存

对于引用类型的参数分配两块内存

方法重载的概念及举例:

public static void main(String[] args) {

new DiGui().max(2.3f, 3.8f);

new DiGui().max(2, 1);

new DiGui().max("123", "1");

new DiGui().max(1, 2, 3);

}

public void max(int a , int b){

System.out.println(a > b ? a : b);

}

public void max(float a , float b){

System.out.println(a > b ? a : b);

}

public void max(String a , String b){

System.out.println(a.length() > b.length() ? a : b);

}

public void max(int a , int b , int c){

System.out.println(b > (a > c ? a : c) ? b : (a > c ? a : c));

}

/*什么叫做方法的重载,就是方法的 名字 和

* 返回值 一样,但是方法里面的参数不同,

* 参数不同包括两个方面:

* 1.参数的个数不一样

* 2.参数的类型不一样

* 至少满足其中一个条件

* 方法重载的好处在于解决了当很多的方

* 法它们需要用到同样的名称,但是它们的

* 方法却需要传入不同参数的问题,比如我

* 想要比较两个int数的大小,两个float类

* 型数字的大小......

* 它们只是传入了不同的参数而已,但是它

* 们的名称都是去较大的那个,就是max,而

* 且也不需要返回值,所以这个地方就应该

* 用方法重载来实现,而如果给每一个都定

* 义一个名称不同的方法,那就太繁琐,太

* 难记了,而且还会出现这种情况,就是比如

* 我要定义一个button,button具有不同的

* 类型的button,有的时候我需要的是这个

* button只需要有一个名字属性就行了,但

* 是后面也许有个button我要有其他的属性

* 等等,所以我的目的就是new一个button

* 如果不用重载的话,那么就只有一种情况

* 能使用button这个名字,那就太不方便了.

*当然这个是构造方法的重载

*如果两个方法的的返回值不一样,但是名字

*一样那叫做方法的重名,在java中是不允许

*的.

*总之,方法的重载时为了让程序变得更加的

*灵活好用.

*/

方法重载中的小问题

public static void main(String[] args) {

new DiGui().max(1, 2);

short j = 10;

short k = 11;

new DiGui().max(j, k);

}

public void max(int a , int b){

System.out.println(a > b ? a : b);

}

public void max(short a , short b){

System.out.println("short");

System.out.println(a > b ? a : b);

}

/*

*第一个表达式它调用的是max(int a,int b)

*因为java一旦看到了整数就是当成int来处理

*如果想要调用max(short a , shrot b)的方

*法,对不起,必须先要把调用的参数设置为short

*类型才行.

*可以对它进行验证,就是输出一个字符串就可以

*了,验证的简单方法就是向被调用的方法中打印

*一个字符串就可以了,结果就是第二个调用的是

*max(short a , shrot b)这个方法

*/

方法的重写:子类对父类里面的方法的实现不满意的

时候就去重写这个方法,很显然只是对方法{}内部的

东西进行修改的.

非静态的方法针对每个对象进行调用,否则不能调用

方法只有在调用的时候才会占内存,否则只是代码

遇到复杂表达式时从里面向外面分析

再为方法命名的时候,要注意英文的习惯,站在使用者

的角度去为它命名,而且对于动词来说大多数都会带上s

这是因为第三人称的原因

this关键字

this指的是你所调用的对象,就是你目前调用的对象

this可以看成时对当前对象的引用

当不能确定一个参数到底指的是哪一个变量的时候,

就拿最近的来声明

静态变量:就是没有实例化它也是存在的,它是属于类的

不属于单独的某个对象

对静态变量的访问:任何一个对象都可以对静态变量进行

访问,而且访问的时候都是访问的同一块内存,即便是没有

对象也可以用类对它进行访问

比如System.out中"out"就是静态的,因为System是,类名

包是为了解决类重名的问题而引入的,它必须作为源代码的第一行

如果有注释放在前面不算,注释不算做代码

打包文件为.jar文件的方法,首先把目录定位到包含class文件的

最上层的文件夹,然后输入如下的命令:

jar cvf test.jar *.*

test.jar代表的是生成的文件的名字,而*.*代表的是当前目录下的

所有的文件.

继承:在一个子类继承父类的时候,在内存里面的情况是,new出来的

对象内部会拥有一个父类对象,所以说子类是包含父类的,子类都比

父类要大,只是需要注意的是如果父类里面出现了

private 或者默认的default 所修饰的属性或者方法的情况下虽然

子类也全部继承了父类的属性,但是它却不一定可以使用它们.

当new了一个子类的时候,它在堆内存中所指向的内存会拥有一个

父类的对象,这个时候对于new出来的对象而言,this指的是这个被

new出的对象本身,而如果要是想访问这个对象中所包含的父类对

象的话就要用super这个关键字了

具体情况看下面

本类内部 同一包 子类 任何地方

private 可以

default 可以 可以

protected 可以 可以 可以

public 可以 可以 可以 可以

继承:子类会继承父类的所有的属性,但是不一定有使用的权利.

所以,一个类的子类能不能使用或者访问父类里面的属性,即跟它父类中的

变量访问修饰符有关,又跟子类和父类的相对位置有关

比如:父类的一些属性的变量访问修饰符为private,那么无论如何子类

都是不能使用的,如果父类的修饰符为protected或者是public无论如

何都是可以使用的,但是如果父类的变量访问修饰符为default的话,那

只有子类跟父类是处在同一个包里面才可以使用的.

另外default也被称为是:包权限访问修饰符.

因为除了自身外就只有同一包的可以访问了

而protected则被称为:子权限修饰符,因为除了本类内部,即同一个包之

外就只有子类可以访问了.

不过继承的时候,子类会继承父类的所有的属性

有时可能会有这样的疑问就是为什么new了一个新的对象如下面所示:

public class Animal {

String name;

int age;

public void display(){

System.out.println("Name:\t" + this.name+"\t Age:\t" + age);

}

}

我在另外的一个包里的一个类中new了一个Animal可是我还是访问不了

它的name 比如 a=new Animal();

其实这个地方犯了一个错误就是,a它代表的不是Animal类的本身,而是它

的一个实例,这个实例在实例化的过程中因为位置的原因它实例化的过程

中父类的所有属性根本虽然被实例化出来,但是它却没使用的权限,因为这

个实例a它是位于另外的一个类里面的

其实说到底,类成员的访问修饰符之所以会存在目的也就是在于,虽然这个

类写出来是为了方便其他类来调用的,但是呢,它本身里面的一些东西是不

能被其他的类所访问到的,这也是处于安全的考虑.

当然类本身也会有访问修饰符修饰的,这种情况也是为了让其他的类来调

用它来设计的,

重写的时候要记得把要重写的方法的声明给复制过来,然后再继续写它里

面的内容.

重写的方法的访问权限不能比被重写的方法使用更严格的修饰符.

继承中的构造方法:

上面已经说过了,在子类实例化的过程中,一定是先生成一个父类的对象,

那么父类对象的生成,必然要调用父类的构造方法,如果子类在实例化的

过程中也是调用的父类的构造方法的话,那么就必须把super.构造方法

写在第一行,就是必须先要有父类才会有子类的意思.

1.子类的构造过程中必须调用父类的构造方法

->隐式的调用,就是父类中存在着不带参数的构造方法

->显示的调用,就是父类中没有不带参数的构造方法,这个时候就必须

要在子类的构造方法中去显式的调用父类的带参数的构造方法了.

2.子类可以在自己的构造方法中使用super(argument_list)来调用基类

的构造方法

->使用this的关键字来调用本类另外的构造方法

->如果调用super则必须写在第一行super()中是父类的构造函数中的

参数

3.如果子类的构造方法中没有显示的调用父类的构造方法的话,则系统默

认的调用父类中没有参数的构造方法.

4.如果子类中既没有显示的调用父类的构造方法,而父类中又没有无参数

的构造方法的话,系统就会报错.

总结:如果父类中没有无参数的构造方法,那么子类在构造方法中就必须的

显示的调用父类的构造方法,否则就会出错,如果父类中有无参数的构造方

法的话,那么系统就会自动的子类构造方法中默认的去调用它.

从原理上讲是因为在子类调用构造方法的时候也就是它要进行实例化了,

这个过程中首先要执行的是父类实例化的构造方法,既然父类里面没有无

参数的构造方法,那么系统自然无法自动的去调用了,不过如果没有无参数

的构造方法,那就说明父类肯定有有参数的构造方法存在,但是系统还必须

要生成父类的对象,因此在子类的构造方法中就必须显示的去调用父类里

面的带参数的构造方法了,之后子类就可以继续的去完成自己的构造方法

了.

成这个父类的对象,

equals方法与==方法在大多数情况下是一样的,但是对于String,date

还有基本类型的包装类都重写了equals的方法.

这些类来说,java已经重写了它们的equals方法,所以即便是new了两个

相同的String去比较结果也是true,当然也只有这几个类重写了,其他的

都是从object继承来的.

重写equals方法的步骤:

1.判断传进来的参数是否为空,为空返回false

2.判断传进来的是否是所需的类型,否则返回false,若是则先对他进行强制

的转换,然后跟当前的对象的属性进行比较就可以了.

instanceof所关注的是一个对象的实际存在形式,所以即便是用父类的形

式来new一个子类的对象,对 instanceof运算符来说也是子类的对象,可是

这个时候因为是以父类对象来new出来的所以它不能访问除了父类对象中

所拥有的属性之外的属性,但是如果非要去访问不可,那么就要加上强制转换

这样转换之后再内存中强制转换后的对象就会指向new出来的子类的实例

也就是相当于用子类的形式重新的new了一个子类的对象.

可扩展性:指的是在创建好了一个程序之后,在后来对它的功能进行扩充的时候

尽可能的不去修改程序的主结构.

就像要在盖好的大楼边上加上一厕所,如果要是为了加一个厕所就需要把大楼

给拆掉重写盖一遍,这就叫做课扩展性不好.

如果以方法中需要传入的参数是父类型的参数,但是实际传入的是子类型的

对象,那么在方法中调用传入对象的方法的时候,它调用的实际是子类型中重

写过的方法,这就是多态,为什么呢?传入的是子类型的对象,也就是说子类型

是事先已经new好的,这个时候呢,在子类型中就会生成一些指针,这些指针它

会指向code segment中一块特定的区域,它保存的是父类及子类中相关联

的方法,这些以子类的形式new出来的对象会指向子类的方法,不过这些只会

在方法被调用的时候才会体现出来,所以叫做动态的绑定,也叫做多态.它的

可扩展性达到了最好.

多态现象出现的几个要素:

1.要有继承

2.要有重写

3.父类引用指向子类对象

多态的出现的原理是被传入的对象在调用里面的方法的时候是根据实际的

对象类型来调用的,而不是根据引用类型来调用的,否则多态就没有意义了.

也更谈不上什么可扩展性了,这里面要注意的是父类引用指向子类对象的

时候调用的只能是重写之后的方法二不能调用其他的非重写的方法和属(

指的是子类里面的特有的属性)

一个类里面如果有了抽象的方法就相当于这个类里面出现了并不能运行的方法

那么这个方法就没有实际的意义,而且假如这个类它可以不是抽象类的话,那么根

据它所new出来的对象就是残疾的类,因为它有些方法是不能实现的,那么这样的

对象就没有实际的意义了,同样这样的类也没有实际的意义,但是这样的类又有存

在的必要,因此就把它们加上一个abstract抽象来作为抽象类.

对于抽象类的子类如果也是抽象类的话,它就可以不去实现父类中所定义的抽

象的方法.

final的用途就是对于被它修饰过的变量时不能够被改变的.只要是它修饰的变量

一旦拥有了值之后这个值就会永远的保存下去直到程序结束为止.

java里面的接口的出现时为了解决java中不能有多继承的这个问题的

其实实现的本质跟继承差不多,所以它里面也支持多态这个特性.

其实在new一个子类的对象的时候,在堆空间里面就会生成一个函数指针指向子类

里面重写父类里面的方法的方法

在以接口的形式去new一个实现了接口的类的时候,对于这个对象的引用来说它只

能够访问到接口中所定义的方法和属性,而访问不到此类里面所定义的额外的方法

和属性,这个就可以实现多态的功能了已经,因为接口中所实现的方法它都已经实现

了.

所以每一个接口它暴露的是每个对象的一部分方法.

接口可以继承接口

类和类之间可以继承

类和接口之间只能实现

如果一个类实现了两个不同的接口,并且这两个接口中都有同样的一个返回值,参数

和名字完全一样的方法,那么这个类可以通过编译,并且这两个接口都可以看到这个

方法,但是如果两个接口中都出现了一个方法名一样,但是返回值不一样的方法的时

侯就不能通过编译了,因为在此类被实例化的时候它就不知道你将要调用哪个方法了.

系统就会出问题,这也是系统的一个bug

所有的关键字都可以修饰内部类.

转载地址:http://blog.csdn.net/tengdazhang770960436/article/details/7484628
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: