黑马程序员——java基础---面向对象(一)

时间:2023-02-14 11:52:11
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------



面向对象(一)

一、概述

        面向对象是相对于面向过程而言的。面向对象和面向过程都是一种编程思想,面向过程强调的是功能行为;面向对象则是将功能封装成对象,强调具备了功能的对象。面向对象是基于面向过程的!

        在我们的现实生活之中,需要完成一件事情,有的人会按照自己的解决思路设计好步骤,然后一步一步的去走下去,这是一种面向过程的思想。而有的人却不管你有多少步,我只要指挥具备解决这个问题能力的对象去做这件事情就行了,而这就是面向对象的思想。

        面向对象的思想是很符合人们的思考习惯的。它可以讲复杂的问题简单化,不需要考虑那么多步骤,而是直接拿对象使用其功能就行了。所以,面向对象思想将程序员从执行者的地位变成了指挥者。

       在用面向对象的思想完成需求时:

                                                           1、首先要去找具备解决这个需求的对象来使用。

                                                           2、若该对象不存在,则需要创建一个具备解决问题能力的对象。

                                                           3、当再次遇到相似需求时,可以直接使用该对象,提高了代码的复用性。

        面向对象思想完成需求需要有两个过程:开发过程中,其实就是不断的构建对象,使用对象,指挥对象做事情。

                                                                         在设计过程中,则是管理和维护对象之间的关系。

        面向对象有三大特征:封装,继承,多态。

二、类与对象之间的关系

        我们之所以使用计算机语言,就是为了利用计算机来描述现实世界中的各种事物,解决我们所不能解决的问题。在java中,我们对事物的描述通过类的形式来体现,类是具体事物的抽象,是概念上的定义,而对象既是该类事物的实实在在的个体。

        在现实生活中,有一个人姓名叫“张三”,年龄是19岁,又有一个人名叫“李四”,年龄是26岁。如果我们抽取出这些人中所具备的共性内容,比如:姓名,年龄等,这就构成了一个类,而这个类具体描述到一个具体的人就形成了对象。

        在现实生活中,描述一个事物无非就是说明其属性和行为,如:人这一事物有:姓名,年龄,体重,身高等属性,和吃饭,睡觉,编程序等等的行为。在java中用class类来描述事物同样也是这样的,其中:

                                                                属性:对应着类中的成员变量

                                                                行为:对应着类中的成员函数

        而我们定义类,则就是在定义类中的成员变量和成员函数。

        现在我们来定义一个类,利用类来实例化一个对象:

package com.itheima;
class Person{
    String name="张三";//定义属性
    int age=24;
    public void show(){//定义行为
        System.out.println(name+"-------------"+age);
    }
}
public class PersonDemo {
    public static void main(String[] args){
        Person p=new Person();//建立对象
        p.show();//使用对象功能
        p.name="李四";//修改成员变量
        p.age=22;
        p.show();
    }
}
        在上面例子中,name和age都是成员变量,而在函数体中,也有一部*部变量,他们有什么区别呢?

        成员变量:它作用于整个类中,随着对象的创建而创建在堆内存中,它被创建就要初始化。

        局部变量:作用于函数体范围类,创建在栈内存之中,它被创建不会初始化,它作用一结束就会立马释放内存空间。

        那么,对象在内存中是如何存储的呢?

        以Person p=new Person(); 为例,该对象一被创建,就会在堆内存中开辟一个空间,生成该空间地址并将该对象的成员变量存放其中。同时,栈内存也会开辟一个名为p的空间,将空间地址传入其中,作为该对象的引用。

        其实,在类的实例化中,不仅仅有Person p=new Person();这样的实例化格式,还可以使用匿名对象。匿名对象是对象的简化格式,其格式为new Person(),它在两种情况下可以使用:

        1、当对对象方法只是一次调用时。

        2、匿名对象可以作为实际参数进行传递。

三、类的三大特性之封装。

        所谓封装,就是指将对象的属性和行为的具体细节进行隐藏,仅仅对外提供公共的调用方法。这就好比一个人要买电脑,但是他不懂电脑的行情,所以就请一个朋友代买,在这种情况下,他就调用了朋友这个对象的公共方法,这样他不需要懂电脑的行情就可以买到满意的电脑。

        封装有以下四大好处:

        1、将变化隔离,我不需要知道该调用方法内部是怎么变化的,我只要知道用这个方法能解决问题就行了

        2、便于使用,封装之后,我在遇到同样的问题就可以多次使用该方法,快捷便利

        3、提高重用性

        4、提高安全性,封装之后,内部的变化外人是无法修改的,可以有效的防止外人的破坏

        封装原则:将不需要对外暴露的内容都隐藏起来,只提供公共的方法对其访问。

        封装关键字:private

        private关键字是一个权限修饰符,它用于修饰成员函数和成员变量,被修饰的成员只能在本类之中有效

        private最常用的手法就是将成员私有化之后,对外提供get或者set方法对其访问,提高了数据的安全性。  

package com.itheima;
class Person{
private String name="张三";//定义属性,私有化
private int age=24;
public void setName(String s){//对外设置set和get方法
this.name=s;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void show(){//定义行为
System.out.println(name+"-------------"+age);
}
}
public class PersonDemo {
public static void main(String[] args){
Person p=new Person();
p.show();
p.setName("李四");//使用set方法来重置成员变量
p.setAge(22);
p.show();
}
}

四、构造函数和构造代码块

        所谓构造函数,是定义在类内部的一类非常特殊的函数,它的作用是给对象进行初始化,对象建立就会调用构造函数。

        它有三大特点:1、函数名与类名相同

                                 2、无返回值类型

                                 3、不能再函数内写return语句

        注意:在一个类中是可以不定义构造函数的,这样系统会给一个默认的为空构造函数,其形式为:XXX(){}。

                   在一个类中可以有多个构造函数,它们是一重载形式存在的。

                   若已经定义了自己的构造函数,则系统给与的默认构造函数就会不再存在了。

        例子:

package com.itheima;
class Person{
private String name="张三";//定义属性,私有化
private int age=24;
Person(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String s){//对外设置set和get方法
this.name=s;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public void show(){//定义行为
System.out.println(name+"-------------"+age);
}
}
public class PersonDemo {
public static void main(String[] args){
Person p=new Person("李四",20);
p.show();
}
}

        在一个类中除了定义构造函数之外还可以定义构造代码块,构造代码块和构造函数一样,也是在对象一确立都开始调用,对对象进行初始化。但是,构造代码块的执行顺序在构造函数之前,也就是说,一个对象初始化过程是先执行构造代码块再执行构造函数,而且,构造代码块是对同类的所有对象进行初始化,而构造函数是对某一个对象的具体初始化。其结构如下

package com.itheima;
class Person{
private String name;//定义属性,私有化
private int age;
{
System.out.println("这是一个人对象,它的成员变量有姓名和年龄");//构造代码块,对所有同类对象初始化,先与构造函数执行
}
Person(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String s){//对外设置set和get方法
this.name=s;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public void show(){//定义行为
System.out.println(name+"-------------"+age);
}
}
public class PersonDemo {
public static void main(String[] args){
Person p=new Person("李四",20);
p.show();
}
}

五、this和static关键字。

        this关键字主要用于区*部变量和成员变量同名的情况,它代表着其所在函数所属对象的引用。那么this关键字何时使用?

        当定义类中功能时,该函数内部需要用到该类对象的成员时,用this来表示这个对象,但凡本类功能中使用了本类对象都要使用this。

        this还可以用于构造函数之间的调用,而且this语句只能定义在构造函数的第一行。

package com.itheima;
class Person{
private String name;//定义属性,私有化
private int age;
Person(){
System.out.println("这是一个人对象,它的成员变量有姓名和年龄");
}
Person(String name){
this();
this.name=name;
}
Person(String name,int age){
this(name);
this.age=age;
}
public void setName(String s){//对外设置set和get方法
this.name=s;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public void show(){//定义行为
System.out.println(name+"-------------"+age);
}
}
public class PersonDemo {
public static void main(String[] args){
Person p=new Person("李四",20);
p.show();
}
}

        static关键字主要用于修饰成员变量或者成员函数。当成员被static修饰之后就多了一种调用方式,该成员除了可以被对象调用之外,还可以直接被类名调用,方式为:类名.静态成员。

        static修饰的特点:

        1、随着类的加载而加载。

        也就是说,静态会随着类的存在而存在,随着类的消失而消失,存在的生命周期最长。

        2、优先于对象存在。

        明确一点:静态是先存在,对象是后存在的。

        3、被所有对象所共享。

        4、可以直接被类名所调用。

        注意:静态方法只能访问静态成员。静态方法中不可以用this,super关键字,主函数是静态的

        实例变量和类变量的区别:

        1、存放位置

         类变量随着类的加载存在于方法区中。

         实例变量存在于堆内存中。

         2、生命周期

         类变量随着类的加载而产生,生命周期很长。

         实例变量随着类实例化产生,生命周较短。

         那么,静态何时使用?

         要从两方面下手:因为静态修饰的内容有成员变量和函数。

         什么时候定义静态变量(类变量)呢?当对象中出现共享数据时,该数据被静态所修饰。对象中的特有数据要定义成非静态存在于堆内存中。

         什么时候定义静态函数呢?当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。

         静态最广泛的应用就是工具类了。在这样的类中,每一个成员函数都被定义为静态的,因为该功能没有访问到非静态数据,它只是作为一种对数据的操作方式。

         构造函数有构造代码块,静态也有静态代码块,它先于静态成员在类加载后抢先执行(静态方法不被调用时不会执行的,但是静态代码块中的代码是只要类加载进入方法区就立马执行),用于给类初始化而且只会执行一次。

package com.itheima;
class Person{
private String name;//定义属性,私有化
private int age;
static String country="CN";//因为国籍是每一个中国人共享的数据,所以可以定义成静态,它随着类的加载而存在于方法区中,可以直接用类名来调用
{
System.out.println("这是一个构造代码块正在执行");
}
Person(){
System.out.println("这是一个构造函数正在执行");
}
Person(String name){
this();//只能存在于构造函数第一行
this.name=name;
}
Person(String name,int age){
this(name);
this.age=age;
}
public void setName(String s){//对外设置set和get方法
this.name=s;
}
static{
System.out.println("这是一个静态代码块正在执行");
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return this.name;
}
public void show(){//定义行为
System.out.println(name+"-------------"+age);
}
}
public class PersonDemo {
public static void main(String[] args){
Person p=new Person("李四",20);
p.show();
System.out.println(Person.country);//country可以被类所调用,因为它是静态的!
}
}                                                                

六、对象被实例化过程。

         从上面代码的运算结果不难看出,对象被实例化的过程一共是经历八个步骤:

         1、类被加载进方法区

         2、执行类的静态代码块

         3、在堆内存中分配空间,产生空间地址

         4、对对象的成员进行原始初始化

         5、对成员进行自定义初始化

         6、执行构造代码块

         7、执行构造函数

         8、将产生的空间地址传入栈内存的空间中

七、单例设计模式。

         所谓设计模式就是解决某一类问题的行之有效的方法,在java中一共有23种设计模式,我们现在介绍一种:单例设计模式。

         所谓单例设计模式就是要求一个类只能有一个对象,不能再产生别的对象的设计类的方法,如何来做呢?

         1、为了保证一个类不要产生过多的对象,我们可以将构造函数私有化,这样就会使该类不能再外部初始化。

         2、不能再外部初始化,就必须在类的内部初始化一个对象,该对象不能被直接访问,所以是私有的。

         3、必须在类内部定义一个获取该对象的方法来让其他方法来访问该单例对象。

         该单例设计模式可以分为懒汉式和饿汉式:

         饿汉式:

package com.itheima;
class Single{
static private Single s = new Single();
private Single(){};
public static Single getSingle(){
return s;
}
}
          懒汉式

package com.itheima;
class Single{
static private Single s = null;
private Single(){};
public static Single getSingle(){
if(s==null)
s = new Single();
return s;
}
}
        注意懒汉式的同步形式:

package com.itheima;
class Single{
static private Single s = null;
private Single(){};
public static Single getSingle(){
if(s==null)
synchronized(Single.class){
if(s==null)//注意必须是双层判断,不然不行!
s = new Single();
}
return s;
}
}




------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------