黑马程序员—【Java基础篇】之面向对象

时间:2023-02-14 12:34:29
------- android培训java培训、期待与您交流! ---------

    这篇分享和总结Java之面对对象。

    主要学习型内容有:1.面向对象概念;2. 类与对象的关系;3 .封装;4. 构造函数;5. this关键字;6 static关键字;7 单例设计模式。一共七个部分,接下来一一总结。黑马程序员—【Java基础篇】之面向对象黑马程序员—【Java基础篇】之面向对象

一、面向对象概念

    第一句话:万物皆对象。传说这是老妖精才能说的话,我们现在说,是很装格调哈,来起吧,伙伴们。

    “java是一种面向对象的编程语言,也就是说对象是这种语言的基础,没有对象了,就没有了java。”我个人觉得这句话很经典,所以就接过来用一下。

    举个例子:如把鸡蛋装进冰箱。

    c语言强调的是功能行为:打开冰箱——>把鸡蛋装进冰箱——>关闭冰箱。

   Java面向对象的思想就是强调冰箱具有功能的对象:冰箱打开,冰箱存储,冰箱关闭。感觉上就是过程是你自己亲自在做,而面向对象却是你指挥着对冰箱去做。

1、理解

    一种符合人们思考习惯的思想;可以将复杂的事情简单化;先要去找具有所需的功能的对象来用;将程序员从执行者转换成了指挥者。

    面向对象的三个特征:封装性,继承性,多态性。

    Java的开发过程,其实就是不断的创建对象,使用对象,指挥对象做事情。

    Java设计的过程,其实就是在管理和维护对象之间的关系。多态性。  

       人是一个对象,人有吃饭,睡觉以及学习等等的行为(可称为功能),那么就是将吃饭、睡觉以及学习等功能封装进人这个的事物中,让人去执行这些功能,是人在调用这些方法,从而简化了过程。  

二、类与对象的关系

1、类与对象的关系

    先看一个示例图:


    黑马程序员—【Java基础篇】之面向对象

    图纸就是类;根据图纸造出来的一辆辆汽车就是对象。

       类(class):可以理解为是构造对象的一个蓝图或者模板,是抽象的概念;反过来说,对象是以类为模型创造的具体实例,是对类的一种具体化、形象化。
        类:对生活中事物的描述
        对象:对类的具体实现,是实实在在存在的实体。
       例如:汽车的设计
        类:指的是汽车的设计图纸
        对象:指实际生产出来的汽车。

/** 
需求:定义一个汽车类,要求设计出汽车的型号(即名字),颜色,轮胎个数,行驶速度,并且让汽车行驶起来(即打印出每个汽车的颜色、轮胎数、速度)并比较两辆汽车之间那个性能更好:即速度快慢
思路:
1.创建一个构造函数,即一个汽车类,对其的颜色,轮胎数
2.创建一个汽车对象,实现其功能
3.构造一个方法,比较两辆车之间的速度
*/
class Car{
String name;
String color;
int nums;
double speed;
Car(String name,String color,int nums,double speed)
{
this.name = name;
this.color = color;
nums = 4;
this.speed = speed;
System.out.println(name + "是一辆" + color + ",轮胎数是:" + nums + ",可以行驶的速度是:" + speed);
}

public void compare(Car c)
{
if(this.speed > c.speed)
{
System.out.println(this.name + "行驶得更快。");
return;
}
System.out.println(c.name + "行驶得更快。");
return;
}
}

class CarDemo
{
public static void main(String[] args)
{
Car x = new Car("Jeep","红色",4,500);
Car y = new Car("法拉利","橙色",4,600);
x.compare(y);
}
}

   上面汽车的例子中,a、bc是局部变量,定义在了方法中,存在于栈内存中;而name、color、nums和speed都是成员变量,存在于堆内存中,随着类的加载而加载。

2、成员变量与局部变量

   不同处:

(1)作用范围
    a. 成员变量:作用于整个类中;
    b. 局部变量:作用于函数中,或者作用于语句块中;
(2)内存中的位置
    a. 成员变量:在堆内存中,因为对象的存在才在内存中存在;
    b. 局部变量:在栈内存中,随着函数的结束而消亡;
(3)初始化方式
    a. 成员变量:随着类的初始化而初始化,在堆内存中被加载,有默认值,可直接参与运算;
    b. 局部变量:随着方法的加载而加载进栈内存中,无初始化值,必须被初始化才能参与运算;

3、匿名对象

    对象的简化形式:匿名对象。例: new Car();

    匿名对象两种使用情况
   (1)当对对象方法仅进行一次调用的时。
   (2)匿名对象可以作为实际参数进行传递。
注:如果对一个对象进行多个成员调用,必须给这个对象起个名字。

     匿名对象与实名对象的区别:

    但是这个对象实体在方法结束后,垃圾回收机制会将其作为垃圾回收。而非匿名对象则不同,当不使用了,会在某一时刻被回收,或是随着主函数的结束而被回收。

三、封装(Encapsulation)

1、 概念

    指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

2、 好处

    (1)将变化隔离。
    (2)便于使用。
    (3)提高重用性。
    (4)调高安全性。

3、 原则

    (1) 将不需要对外提供的内容都隐藏起来。
    (2) 把属性都隐藏,提供公共方法对其访问。

4、说明

    (1)私有仅仅是封装的一种表现形式,如包也是一种封装形式

    (2)之所以对外提供访问方式,就是因为可以在访问方式中加入逻辑判断等语句,对访问的数据进行操作,提高了代码的健壮性。

5、private(私有)关键字

  (1)用于修饰成员(成员变量和成员函数)
  (2)被私有化的成员只在本类中有效。
  (3)常用之一:
    将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性; 是一个权限修饰符。

    例如:

class Person//描述人对象的类  
{
private int age;//人对象的年龄属性,private(关键字)
public void setAge(int a)//提供访问方法,并判断是否有效
{
if(a>0 && a<130)
{  <pre name="code" class="java"><span style="white-space:pre"></span>age = a;<pre name="code" class="java"><span style="white-space:pre"></span>speak();
<pre name="code" class="java"><span style="white-space:pre"></span>}
else{
System.out.println("非法数值");
<span style="white-space:pre"></span>}
}
public int getAge()//提供公共获取方法,同时返回int值,必须return语句。<pre name="code" class="java"> {
return age;
}
private void speak()//私有说功能
{
System.out.println("age="+age);
}
}

class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();//创建人对象 ,主函数调用。
p.setAge(-50);//利用封装提供public访问方法进行修改年龄属性
p.speak();
}
}
 
 
 
 

四、构造函数

1、 特点

    (1)  函数名与类名相同。

    (2)  不用定义返回值类型。

    (3)  不可以写return语句。

2、 作用

    (1) 给对象进行初始化。

3、注意事项

    当一个类中没有定义构造函数时,那么系统就会默认给该类加入一个空参数的构造函数。当在类中自定义了构造函数后,默认的构造函数就没有了。

4、构造函数和一般函数区别

    运行上不同:     构造函数式在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,给是对象添加对象具备的功能。一个对象建立,构造函数只运行一次。而一般方法可以被该对象调用多次。

5、什么时候定义构造函数?

    当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中。

6、构造代码块

(1) 作用:给对象进行初始化;对象一建立就运行,而且优先于构造函数运行。 (2) 构造代码块构造函数的区别     a、 构造代码块是给所有的对象进行初始化,即每个对象都会有的特性。     b、而构造函数是给对应的对象初始化;     c 、构造代码块中定义的是不同对象共性的初始化内容。

<span style="font-family:SimSun;"><span style="font-size:12px;">class Person
{ private String name;</span></span><pre name="code" class="java"><span style="font-family:SimSun;font-size:12px;"> private int age;
{
System.out.println("Person")//构造代码块
cry();
}</span>
 

五、this知识点

    毕老师上课的一个例子:

class Person  //声明Person类
{
private String name;
private int age;
Person(int age)//局部变量时age,成员变量也是age
{
this.age = age;//对象传进来的age给了全局变量age。
}
Person(String name)
{
this.name = name;//这里用this表示调用构造方法的对象
}
Person(String name,int age)
{
this.name = name;
this.age = age;
}

public void speak()
{
System.out.println("name="+name+"...age="+age);
show();
}
public void show()
{
System.out.println(this.name);
}
}

1、特点

    this代表其所在函数所属对象的引用。换言之:this代本类对象的引用。

2、什么时候使用this关键字呢?

    当在函数内需要用到调用该函数的对象时,就用this。

六、static(静态)关键字

1、 存在的意义

    内存有一片地方是静态方法区,专门存放静态常量和方法的区域,当一个变量或者方法是所有对象都共有的,那么为了提高效率和内存使用率,就产生了static。

 2、 特点

    (1)随着类的加载而加载,在类中生命周期最长;
    (2)优先于对象而存在;
    (3)可以被所有对象共享;
    (4)可以直接被类名调用。

3、用途

    (1)修饰成员:成员变量和成员方法。

    (2)当成员被static修饰后,就多了一种调用方式,即可以被对象和类名调用。

4、静态常量和非静态常量

   (1)静态成员变量又称为类变量。

    (2)非静态成员变量又被称为实例变量。

    (3) 实例变量和类变量的区别

a、存放位置

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

        实例变量随着对象的建立而存在于堆内存中。

 b、生命周期

        类变量生命周期最长,随着类的消失而消失。

        实例变量生命周期随着对象的消失而消失。

5、静态的利弊

(1)利

    可以直接被类名调用。

(2)弊

    存放在内存里, 生命周期过长。
    访问出现局限性。(静态虽好,只能访问静态)

    对对象的共享数据进行单独空间的存储,节省空间。

public class Math
{
public static final double π = 3.14;//final将PI设置为不可再定义的常量
}

  
  如果省略了static,PI就变成了一个实例常量,那么,每一个Math对象就都有自己的一个PI拷贝了,这样的话,对内存也是一种占用。 

class Student  
{
private int id; //定义私有变量id;
private static int studentId = 1; //定义静态 int studentId;
//获取id的访问器
public int getId()
{
return id;
}
public void setId()
{
id = studentId;
studentId++;
}
}

6、静态的应用

/** 
这是一个可以对数组进行相关操作的工具类,该类提供了取数组的最值、排序等功能。
@author 王永华
@version V1.8
*/
//类名权限要最大才能创建说明书文档
public class ArrayTool
{
/**
空参数构造函数
*/
private ArrayTool(); //私有化构造函数是为了让其不能创建对象。
{

}

/**
这个功能用于得到int类型数组中的最大值
@param arr 接收一个int类型的数组
@return 返回接收的该数组的最大值
*/
public static int getMax(int[] arr)
{
int max=0;
for (int x=1;x<arr.length ;x++ )
{
if(arr[x]>arr[max])
max=x;
}
return arr[max];
}

/**
这个功能用于得到int类型数组中的最小值
@param arr 接收一个int类型的数组
@return 返回该数组的最小值
*/
public static int getMin(int[] arr)
{
int min=0;
for (int x=1;x<arr.length ;x++ )
{
if(arr[x]<arr[min])
min=x;
}
return arr[min];
}

/**
对int类型数组进行选择升序排列
@param arr 接收一个int类型的数组
*/
public static void selectSort(int[] arr)
{
for (int x=0;x<arr.length-1 ; x++)
{
for (int y=x+1; y<arr.length; y++)
{
if(arr[x]>arr[y])
swap(arr,x,y);
}
}
}

/**
对int类型数组进行冒泡升序排列
@param arr 接收一个int 类型数组
*/
public static void bubbleSort(int[] arr)
{
for (int x=0;x<arr.length-1;x++ )
{
for (int y=0;y<arr.length-x-1;y++ )
{
if(arr[y]>arr[y+1])
swap(arr,y,y+1);
}
}
}

/**
对数组中的两个元素进行位置交换
@param arr 接收一个int类型的数组
@param a 要置换的元素角标
@param b 要置换的元素角标
*/
private static void swap(int[] arr,int a,int b)
{
arr[a]=arr[b]+(arr[b]=arr[a])*0;
}

/**
遍历数组:打印数组中所有元素,形式为:[elemet1,elemet2,...]
@param arr 接收一个int类型的数组
*/
public static void printArray(int[] arr)
{
System.out.print("[");
for (int x=0; x<arr.length-1; x++)
{
System.out.print(arr[x]+",");
}
System.out.println(arr[arr.length-1]+"]");
}
}
    通过以上我们可以发现,一下将要解决的问题。

    (1) 当每个应用程序都有共同之处,可将其封装,提高其复用性。

   (2) 注意事项

    a. 对象时用于封装数据的;
    b. 对数据的操作方法,若没用到方法中特有的数据,则无需创建对象而占用多余的内存。

   (3)静态代码块

    a. 随着类的加载而执行,且优先于主函数;     b. 只执行一次,类再创建对象,则不再执行,已经存在于内存中。
   格式:

static  
{语句};

七、单例设计模式

1、概念

   解决某一问题最行之有效的方法,java*有23种设计模式,其中单利设计模式就是其中一种

2、单例设计模式

   单例设计模式的作用:使一个类在内存中只存在一个对象。

3、单例设计模式的具体表现形式  

        单利设计模式其中具体表现有:饿汉式和懒汉式;其实是两中思维的碰撞。

(1)饿汉式

    特点:先初始化对象

class Single   
{
private Single(){}
private static Single s = new Single();
public static Single getSingle()
{
return s;
}
}

class SingleText
{
public static void main(String [] args)
{
Single s1 = Single.getSingle();
Single s2 = Single.getSingle();
if (s1==s2)
System.out.println(true);
else
System.out.println(false);
}
}

(2)懒汉式

    特点:对象是方法被调用时,才初始化,这也叫对象的延时加载。

class Single   
{
private Single(){}
private static Single s = null;
public static Single getSingle()
{
if (s==null)
s = new Single();
return s;
}
}

class SingleText
{
public static void main(String [] args)
{
Single s1 = Single.getSingle();
Single s2 = Single.getSingle();
if (s1==s2)
System.out.println(true);
else
System.out.println(false);
}
}

    相比之下,我个人理解,第1种会占用内存一些,第二种少占内存一些,更加贴和,却又存在线程的安全问题。总体而言饿汉式比懒汉式更可靠。    

    今天到这里吧,小伙伴们明天见。