面向对象和面向过程
面向对象是一种以事物为中心的编程思想。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为,面向对象是将事物高度抽象化。
面向过程是一种以过程为中心的编程思想。面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候依次调用即可,面向过程强调的是工作的执行。
面向对象是相对于面向过程而言,站在面向对象的角度去看问题,你是对象的动作的指挥者;站在面向过程的角度去看问题,你是动作的执行者。
对象和类
对象是类的一个实例;对象主要通过new关键字,newInstance()方法,clone()方法,工厂方法和反序列化方法创建;对象根据需要创建可创建多次;对象在创建时分配内存。
类是创建对象的蓝图或模板;只能根据class关键字来定义类;类只声明一次;类的创建不需要分配内存。
成员变量和局部变量
成员变量:成员变量定义在类中,在整个类中都可以被访问;成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中;成员变量有默认初始化值。
局部变量:局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效;局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放;局部变量没有默认初始化值
若成员变量没有设置属性值,成员方法中同名局部变量也没有定义变量类型,那么该局部变量其实就是成员变量。
匿名对象
没有引用类型变量指向的对象称作为匿名对象,所以不会给匿名对象赋予属性值,因为永远无法获取到,并且两个匿名对象永远都不可能是同一个对象。
匿名对象好处:1、简化书写 2、节省内存
匿名对象的应用场景:1、如果一个对象需要调用一个方法,调用完这个方法之后,该对象就不再使用了,这时候可以使用匿名对象。执行完毕后该对象就变成垃圾,可以被GC回收 2、可以作为实参调用一个方法。
面向对象-封装
封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装起来,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其它对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互,用户无须知道对象内部的细节,但可以通过该对象对外的提供的接口来访问该对象。
- 良好的封装能够减少耦合
- 类内部的结构可以自由修改
- 可以对成员进行更精确的控制
- 隐藏信息,实现细节
public class Husband {
/*
* 使用private修饰符对属性修饰
*/
private String name ;
private String sex ;
private int age ;
private Wife wife;
/*
* setter()、getter()是该对象对外提供的接口
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
public class Wife {
/*
* 使用private修饰符对属性修饰
*/
private String name;
private int age;
private String sex;
private Husband husband;
/*
* setter()、getter()是该对象对外提供的接口
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(int age) {
this.age = age;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
public Husband getHusband() {
return husband;
}
}
上面两个封装实例中Husband里Wife引用没有getter()方法,同时Wife的age没有getter()方法。封装其实就是把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果不想被外界方法,那么就不提供方法给外界访问;可是如果一个类没有提供给外界访问的方法,那么这个类本身也没有存在的意义。
通过这个我们还不能真正体会封装的好处,现在从程序的角度来分析封装带来的好处。如果我们不使用封装,那么该对象就没有setter()和getter(),那么Husband类应该这样定义和使用:
public String name ;
public String sex ;
public int age ;
public Wife wife;
Husband husband = new Husband();
husband.age = 30;
husband.name = "张三";
husband.sex = "男";
如果哪天需要修改Husband,例如将age修改为String类型?你只有一处使用了这个类还好,如果你有几十个甚至上百个这样地方,不是要改到崩溃。如果使用了封装,完全可以不需要做任何修改,只需要稍微改变下Husband类的setAge()方法即可。
public class Husband {
/*
* 使用private修饰符对属性修饰
*/
private String name ;
private String sex ;
private String age ;
private Wife wife;
/*
* setter()、getter()是该对象对外提供的接口
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(int age) {
this.age = String.valueOf(age);
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
还是那个Husband,一般来说在引用这个对象的时候是不容易出错的,但是有时由于不小心,可能会写成这样
Husband husband = new Husband();
husband.age = 300;
使用封装可以避免上面的问题,对age的访问入口做一些控制(setter()):
public class Husband {
/*
* 使用private修饰符对属性修饰
*/
private String name ;
private String sex ;
private int age ;
private Wife wife;
/*
* setter()、getter()是该对象对外提供的接口
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 120){
// 错误提示
System.out.println("ERROR:error age input....");
}else{
this.age = age;
}
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
上面都是对sette()方法的控制,其实通过使用封装也能够对对象的出口做出很好的控制。例如性别我们在数据库中一般都是已1、0方式来存储的,但是前台又不能展示1、0,这里只需要在getter()方法里面做一些转换即可。
public String getSexName() {
if("0".equals(sex)){
sexName = "女";
}
else if("1".equals(sex)){
sexName = "男";
}
else{
sexName = "人妖???";
}
return sexName;
}
构造方法
1、构造方法的名称总是和它的类名一致。
2、构造方法没有返回值,即不可以为它指定任何类型的返回值,包括void。
3、在构造方法的第一条语句中,可以调用同类的另一个构造函数或者父类的构造函数。
4、构造方法是在创建对象时由jvm调用,而不是由编程人员显式直接调用。
5、构造方法的主要作用是完成对类对象的初始化。
6、类中没有定义构造函数时,系统会默认添加一个无参的构造方法。
7、类中自定义构造方法之后,默认的无参构造方法消失,如果需要无参构造方法需手动添加。
构造代码块
面向对象-继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。
public class Person {
protected String name ;
protected String sex ;
protected int age ;
}
public class Husband extends Person {
private Wife wife;
}
public class Wife extends Person{
private Husband husband;
}
Wife、Husband使用继承后,不但代码量减少,而且能够明显看到他们的关系。继承所描述的是“is-a”的关系,如果有两个对象A和B,若可以描述为“A是B”,则可以表示A继承B,其中B是被继承者称之为父类或者超类,A是继承者称之为子类或者派生类。实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性;同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”。
继承定义了类如何相互关联,共享特性。对于若干个相同或者相似的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。
使用继承时需要记住三句话:子类拥有父类非private的属性和方法;子类可以拥有自己属性和方法,即子类可以对父类进行扩展;子类可以用自己的方式实现父类的方法。
通过前面我们知道子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的---构造器。对于构造器而言,它只能够被调用,而不能被继承。 调用父类的构造方法我们使用super()即可。对于子类而已,其构造器的正确初始化是非常重要的,而且当且仅当只有一个方法可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。