黑马程序员:面向对象---学习笔记

本文是面向对象编程的学习笔记,详细介绍了面向对象的基本概念、类与对象的关系、封装、构造函数、构造代码块、this关键字、static静态成员及静态方法。通过冰箱的实例对比了面向过程和面向对象的区别,讲解了如何明确一个对象。此外,文章还探讨了设计模式中的单例模式,包括饿汉式和懒汉式的实现,并分析了它们的优缺点。
摘要由CSDN通过智能技术生成
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

黑马程序员:面向对象---学习笔记

面向对象

定义

面向对象就是一种思想,它相对于面向过程而言。

面向过程强调的是功能的行为过程。

而面向对象是将功能封装成对象,强调具备了功能的对象。

面向对象是基于面向过程而来的。

冰箱的举例:

面向过程:打开冰箱  →  存储进冰箱  →  关闭冰箱

面向对象:冰箱.打开       冰箱.存储            冰箱.关闭

面向对象的最高境界:一切皆为对象(我的愤怒在深渊中燃烧。一切皆为灰烬。偷笑总有一种wow的感觉。)

如何明确一个对象:

一般用名词提炼法。

例:人开门

class  
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}

/*
人开门:名词提炼法。
人
{
	开门(门)
	{
		门.开();
	}
}

门
{
	开(){操作门轴等。}
}
*/




面向对象的思想有三个特征: 封装,继承,多态
以后的开发,其实就是在找对象来使用,如果没有对象,那么就创建一个对象。

未来基于面向对象的开发:寻找对象,建立对象,使用对象,维护对象之间的关系。


类与对象的关系:

       类就是对现实生活中事物的描述,对象就是这类事物实实在在的个体。

例:

     类:提取对象的共性内容,对具体的抽象共性:人这个类,具有姓名,年龄,性别..........

    对象:就是类的个体,比如 张三,李四

映射到java中,描述就是class定义的类,具体对象就是对应java中在堆中new建立的实体。

类与对象的关系汽车举例:


可以理解为:汽车图纸就是类,汽车就是在堆内存中存放的对象

package ch01;
/**
 * 建立一个汽车类*/
class Car {
	String color = "红色";//描述汽车的颜色属性
	int num = 4;//描述汽车的轮胎数
	void run (){
		System.out.println("car run!");//描述汽车可以跑起来的方法。
	}
}

class  CarDemo
{
	public static void main(String[] args) 
	{
		Car a = new Car();//创建一个汽车的实例
		System.out.println(a.color);//汽车的颜色
		System.out.println(a.num);//汽车的轮胎数
		a.run();//汽车跑起来了
	}
}
	
以上例子说明了在java中如何定义一个类,如何定义类中的变量和方法,如何创建实例,如何调用实例的方法和属性。

类不用单独运行的时候,是不用写该类的主函数的。

成员变量与局部变量

范围:成员变量作用于整个类中。

            局部变量作用于函数和语句中。

在内存里:成员变量,存在堆内存中,通过对象的加载而在内存中开辟地址存在的。

                    局部变量,存储在栈内存中。

匿名对象

匿名对象就是创建对象的简写方式。

当只需要调用一次对象的时候,那么可以使用匿名对象,会使代码简化。

但是当需要多次调用同一个对象的时候,就不能使用匿名对象,因为每new一次就是创建一个新的对象

格式:

       new Car().num = 5;

       new Car().color= "red";

       new Car().run();

如果需要多次调用的话,那么给对象起一个名字。

   Car a = new Car();
匿名对象的使用方式:

一般匿名对象可以作为实际参数进行传递

封装(Encapsulation)

封装:是指隐藏对象的属性的实现细节,仅对外提供访问方式。

好处:将变化隔离,便于使用,提高代码的复用性,提高程序的安全性。

封装的原则:

        将不需要对外提供的内容都隐藏起来。

        把属性都隐藏,提供公共方法对其访问。

private:私有权限修饰符,用于修饰类中的成员(成员变量,方法)

 上代码:

class Person{ 

	//成员变量不赋值也可以进行运行,默认初始化值是null 
	String name; 
	private int age; //私有化年龄 
	//对外提供公共设置的访问方式 ,可以提高代码的安全性。
	public void setAge(int a){ 
		//加入判断,使程序更为符合逻辑 
		if(a>=0 && a<=120) 
			age=a; 
		else 
			System.out.println("年龄非法"); 
	} 
	//对外提供公共的获取方法 
	public int getAge(){ 
		return age; 
	} 
	//人可以说出自己的名字和年龄 
	public void speak(){ 
		System.out.println("name="+name+"...age="+age); 
	} 
} 

//Person测试类 
public class PersonTest{ 
	public static void main(String[] args){ 
	Person p = new Person(); 
	//对p对象的name属性进行赋值。 
	//p.age=-20//age被直接访问有安全隐患,有非法数据,加关键字private,age默认值是0 
	//p.setAge(-20);失败,因为不符合Person类中年龄的设置规则。 
	p.name="Xcc"; 
	//对p对象的age进行设置。 
	p.setAge(20); 
	//调用p对象的speak方法,打印自己的姓名和年龄。 
	p.speak(); 
	} 
} 

构造函数

也有的书里面叫做构造器,或者说构造方法。

构造函数的特点:

1函数名必须与类名相同

2不用定义返回值类型

3不可以写return语句(这个本人测试过了,可以写return,但是不能return任何返回值,会报错。

格式

class Person {

      Person () {};//空参数的构造函数,当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数

}

对象一建立就会调用与之相关的构造函数

构造函数的作用:

可以用于给对象进行初始化。

构造函数的细节:

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

构造函数与普通函数的区别:

在语法上不同,在运行上也不同。

构造函数是对象已建立就加载的,作用是给对象初始化。

而一般对象是对象调用的时候才运行,是为了给该对象添加相应的对象机能的。

一个对象的建立,构造函数只运行一次,而一般方法,是可以随时调用的。

构造代码块

class Person{ 

	{
		System.out.println(); 
	}
}	
作用:给对象进行初始化。

对象一建立就运行,并且优先级高于构造函数。

与构造函数的区别:

构造代码块是给所有对象进行统一初始化。用来定义共性初始化方式

构造函数是给对应的对象初始化。

总结:构造代码块和构造函数共性的地方就是当对象创建时,就给对象进行初始化一次。

this关键字

特点:  this代表其所在函数所属对象的引用。

换言之:this代本类对象的引用。

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

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

当成员变量和局部变量重名,可以用关键字this来区分。

this:代表对象。代表哪个对象呢?当前对象。

this:就是所在函数所属对象的引用。

简单说:哪个对象调用了this所在的函数,this就代表哪个对象。

它可以在类里面来引用这个类的属性和方法:

public class ThisDemo {  
    String name="Mick";
    public void print(String name){
        System.out.println("类中的属性 name="+this.name);
        System.out.println("局部传参的属性="+name);
    }   
    public static void main(String[] args) {
        ThisDemo tt=new ThisDemo();
        tt.print("Orson");
    }
}
关于返回类自身的引用,Thing in Java有个很经典的例子,

通过this 这个关键字返回自身这个对象然后在一条语句里面实现多次的操作例:

public class ThisDemo {  
    int number;
    ThisDemo increment(){
         number++;
         return this;
    }  
  private void print(){
         System.out.println("number="+number);
    }
    public static void main(String[] args) {
        ThisDemo tt=new ThisDemo();
         tt.increment().increment().increment().print();
    }
}
在一个构造函数中通过 this 这个引用来调用另一个构造函数例:

public class ThisDemo {  
    String name;
    int age;
    public ThisDemo (){ 
        this.age=21;
   }     
    public ThisDemo(String name,int age){
        this();
        this.name="Mick";
    }     
  private void print(){
         System.out.println("最终名字="+this.name);
         System.out.println("最终的年龄="+this.age);
    }
    public static void main(String[] args) {
       ThisDemo tt=new ThisDemo("",0); //随便传进去的参数
       tt.print();
    }
}

static静态

static:用于修饰成员(成员变量和成员函数)

被修饰后的成员具备以下特点:

1.随着类的加载而加载

2.优先于对象存在

3.被所有对象所共享

4.可以直接被类名调用

static特点:

1,  static是一个修饰符,用于修饰成员。(成员函数,成员变量)

2,  static修饰的成员被所有的对象所共享。

3,  static优先于对象存在,因为static的成员随着类的加载就已经存在了。

4,  static修饰的成员多了一种调用方式,可以直接被类名调用。类名.静态成员。

5,  static修饰的数据是共享数据,对象中存储的是特有数据。

成员变量和静态变量的区别

1.两个变量的生命周期不同。

         成员变量随着对象的创建而存在,随着对象的被回收而释放。

         静态变量随着类的加载而存在,随着类的消失而消失。

2.调用方式不同。

        成员变量只能被对象调用。

        静态变量可以被对象调用,还可以被类名.调用

3.别名不同。

        成员变量也称为实例变量。

        静态变量称为类变量。

4.数据存储位置不同。

        成员变量存储在堆内存的对象中,所以也叫对象的特有数据。

        静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

什么时候该用static:

如果某个内容是所有对象共享的,就用静态修饰。

什么时候使用静态成员和函数呢?

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

什么时候定义静态变量(类变量)呢?

当对象中出现可共享的数据时,该数据被静态修饰。

对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态函数呢?

当功能内部没有访问到非静态数据,或者对象的特有数据,

那么该功能可以定义成静态的

使用注意

1.静态方法可能访问静态成员类名.静态成员。

2.静态方法中不可以写this,super关键字,因为静态先于对象操作//编译不过。


静态有利有弊


利处:


对对象共享的数据进行单独空间的存储,没有必要每个对象都存一份


可以被直接被类名.调用


弊端:生命周期过长,访问出现局限性(静态虽好,只能访问静态)


3.主函数是静态的


public static void main(String[] args)


主函数

1,  格式是固定的。(除了args这个数组名字可以变,其他不行)

2,  被Jvm所识别和调用。

public:因为权限必须是最大的。

static:不需要对象的,直接用主函数所属类名调用即可。

void:主函数没有具体的返回值。(因为返一个值给虚拟机,虚拟机也害怕啊!是不是虚拟机没有内存存放)

main:函数名,不是关键字,只是一个Jvm识别的固定的名字。

String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。

静态的应用

/*
静态的应用。

每一个应用程序中都有共性的功能,
可以将这些功能进行抽取,独立封装。
以便复用。


虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。
发现了问题:
1,对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
2,操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。

这时就考虑,让程序更严谨,是不需要对象的。
可以将ArrayTool中的方法都定义成static的。直接通过类名调用即可。

将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。
为了更为严谨,强制让该类不能建立对象。
可以通过将构造函数私有化完成。



接下来,将ArrayTool.class文件发送给其他人,其他人只要将该文件设置到classpath路径下,就可以使用该工具类。

但是,很遗憾,该类中到底定义了多少个方法,对方去不清楚。因为该类并没有使用说明书。

开始制作程序的说明书。java的说明书通过文档注释来完成。
*/



/**
这是一个可以对数组进行操作的工具类,该类中提供了,获取最值,排序等功能。
@author 张三
@version V1.1

*/

//javadoc -d myhelp -author -version ArrayTool.java

public class ArrayTool
{
	/**
	空参数构造函数。
	*/
	private ArrayTool(){}

	/**
	获取一个整形数组中的最大值。
	@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];
	}
	
	/**
	获取一个整形数组中的最小值。
	@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)
	{
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}
	/**
	用于打印数组中的元素。打印形式是:[elemet1, element2, ...]
	*/
	public static void printArray(int[] arr)
	{
		System.out.print("[");
		for(int x=0; x<arr.length; x++)
		{
			if(x!=arr.length-1)
				System.out.print(arr[x]+", ");
			else
				System.out.println(arr[x]+"]");
		}
	}
}

/*
<span style="color:#FF0000;"><strong>一个类中默认会有一个空参数的构造函数,
这个默认的构造函数的权限和所属类一致。</strong></span>
如果类被public修饰,那么默认的构造函数也带public修饰符。
如果类没有被public修饰,那么默认的构造函数,也没有public修饰。
<span style="color:#FF0000;"><strong>
默认构造构造函数的权限是随着的类的变化而变化的。</strong></span>

*/

/*
class Demo
{
	public static void main(String[] args)
	{
		int[] arr = {3,4,1,8};
	

		int max = getMax(arr);
		System.out.println("max="+max);
	}
	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];
	}
}
class Test
{
	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];
	}
}
*/

以上是毕老师给出的静态的应用和。


设计模式:

设计模式是解决某一类问题最行之有效的方法,Java中23种设计模式。

单例设计模式(Singleton):解决一个类在内存中只存在一个对象

比如对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性。


想要保证对象唯一:


为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象;

还为了让其他程序可以访问到该类对象,只好在本类中自定义一个对象;

为了方便其他程序对自定义对象的访问, 可以对外提供一些访问方式;

单例设计模式:饿汉式

Single类一进内存,就已经创建好了对象,简单的说就是一上来就吃。

思路:

将构造函数私有化;

在类中创建一个本类对象;

提供一个公共的访问方法,可以获取到该类对象;


步骤:

class Single {

        //将构造函数私有化,防止创建该类对象

        private Single(){}

        //在类中创建一个本类对象

        private finla static Single single =new Single();

        //提供一个公共的访问方法,将创建的对象作为返回值传回。

        public static Single getInstance(){

                return single;

        }

} 

单例设计模式:懒汉式


对象是方法被调用时才初始化也叫对象的延时加载

Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。


步骤:

class Single {
	//将构造函数私有化,防止创建该类对象
	private Single(){}
	//在类中创建一个空的本类对象
	private static Single single =null;
	//提供一个公共的访问方法,将创建的对象作为返回值传回。
	public static Single getInstance(){
		if(single==null){
			//当多线程访问时会出现安全隐患,把共享资源同步
			synchronized(Single.class){
				//判断是否已经创建过对象,没有的话创建对象
				if(single==null)
					single =new Single();
			}
		}
		//返回创建的对象s
		return single;
	} 
}

为什么有饿汉式还会有懒汉式?

懒汉式与饿汉式的类加载时间不同。

实际开发中用饿汉式,因为在考虑多线程时会比较安全,懒汉式的解决安全问题的方法,双重判断,加入锁

总结:


饿汉式:一上来就对对象初始化。对资源占用比懒汉稍大。

懒汉式:对象调用方法时,才初始化,也叫做对象的延时加载。


实际中因为一点点的效率问题来抛弃更高的维护性与安全性的方法是不可取的。(我是这么认为。)因为软件系统是需要维护的,而且维护性差的话会产生更高的成本,安全性

差必须用更多的测试来保证软件的健壮性,那么成本也是直线上升的。我认为开发程序最重要的就是成本与品质。

以上,关于面向对象,单例的一些笔记和开发的感悟。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值