黑马程序员-JAVASE入门(面向对象,单例模式)

------- android培训java培训、期待与您交流! ----------

面向对象

1 面向对象概念

2 类与对象的关系

3 封装

4 构造函数

5 this关键字

6 static关键字

7 单例设计模式


1:面向对象概念

面向对象就是把多个功能封装到一个对象中,通过调用该对象获取这些功能。称为面向对象。

面向对象和面向过程的理解:

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

事例:
门具有打开,关闭功能等等。这些功能都需要门来完成的,那么就将这些功能封装进门这个对象中,我们只要调用门这个对象,通过门就能使用这些功能。


开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情。
设计的过程:其实就是在管理和维护对象之间的关系。

面向对象的特征:
封装(encapsulation)
继承(inheritance)
多态(polymorphism)


2 :类与对象的关系


使用计算机语言就是不断的在描述现实生活中的事物。
java中描述事物通过类的形式体现,类是一组相同属性行为的对象的抽象。
对象即是该类事物实实在在存在的个体。
举例:人就是一个类(是把每一个相同属性行为的对象进行抽取)人的属性:姓名,年龄,身高,体重等,人的行为:吃饭,睡觉,说话,跑,跳等
而我们就是对象(是实实在在存在的个体),具体每个人叫什么名字,年龄多大,身高多高,体重多重等,吃饭怎么吃,睡觉怎么睡,说话怎么说等
描述任意一类事物就是在描述他的属性和行为


类与对象的关系如图



可以理解为:
类就是图纸
汽车就是堆内存中的对象,创建的实体,那么实体的作用是什么?
用来封装具体数据用的

java中通过new关键字来创建实体。实体其实就是用来封装具体数据用的,如数组就是。对象也是。
Car c = new Car();//通过Car类创建了一个具体对象。该对象如何使用呢。为了方便使用该对象,就给对象起个名字。
等号左边:定义了一个变量,是Car类型的。而Car是一个类,所以c是类类型变量。
类类型变量指定指向对象。//给这个c车,指定颜色和轮胎数。c也是局部变量,存储在栈内存中
 c.color = "red";
 c.num = 4;
 c.run();//指挥车进行运行。调用格式:对象.对象成员
 /*从现实生活过渡到计算机中,
 Car 对应的是生活的图纸。
 new Car(): 对应的是生活中具体的汽车。

创建对象在内存中的图解:



类的定义:
生活中描述事物无非就是描述事物的 属性行为
如:人有身高,体重等属性,有说话,打球等行为。
Java中用类class来描述事物也是如此
属性:对应类中的成员变量。
行为:对应类中的成员函数。
定义类其实在定义类中的成员(成员变量和成员函数)。


成员变量和局部变量的区别:

1,作用范围。
成员变量:定义在类中,作用于整个类。
局部变量:只在它所属的局部大括号中有效。比如函数上的参数,函数中的变量,语句中的变量。
public void function(int x){//x,y,z都是局部变量。
int y = 0;
for(int z=0; z<3; x++){
}//当循环结束时,z在内存中释放。当function函数执行完毕,x和y在内存中释放。
}
2,存储情况。
成员变量:存储在堆内存中,随着对象的存在而存在。当对象变成垃圾被回收时,该该对象中的成员变量会消失。
局部变量:存储在栈内存中,当方法被调用,或者语句被执行的时候,才存在。
当方法运行完毕,或者语句运行完毕时,局部会被自动释放。所以成员变量也称之为实例(对象)变量.
3,初始化情况。
成员变量:在堆内存中有默认初始化值。
局部变量:必须手动初始化后,才可以被使用。


匿名对象:

所谓的匿名对象,就是创建对象的时候没有给对象起名字就直接使用。

使用方式:

1)使用方式一:当对对象的方法只调用一次时,可以使用匿名对象来完成,这样写比较简化。

      如果对一个对象进行多个成员调用,必须给这个对象起个名字

2)使用方式二:可以给匿名对象作为实际参数进行传递,从而可以不用在main方法中创建一个变量,提高了编程效率,减少了代码书写。

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

匿名对象常见错误理解:

如:

1:new Car().num = 5; 

2: new Car().color = "blue";

 3:new Car().run();//假设有run方法能调用num和color属性

new三次就是三个匿名对象。3方法打印出来的不是1,2所定义的属性。因为三者没有关系。属于三个对象了


3:封装

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
将变化隔离。
便于使用。
提高重用性。
提高安全性。
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。

1:private :私有,权限修饰符:用于修饰类中的成员(成员变量,成员函数)。
私有只在本类中有效。
当成员私有后,提高了安全性。但是访问权限降低了。这时可以通过对外提供公有方法的形式对其进行访问。
处是:可以在方法中对成员变量的访问进行控制。
注意:私有仅仅是封装的一种体现形式而已。

常用之一:
将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性。

2:构造函数:

构造函数的特点:
1.构造方法的方法名必须与类名相同。
2.构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。不用写return语句
3.构造方法不能由编程人员调用,而要系统调用。
4.一个类可以定义多个构造方法,也就是构造方法可以重载,以参数的个数,类型,或排列顺序区分。
5. 构造函数细节:如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
6. 作用:构造方法的主要作用是完成对象的初始化工作,它能够把定义对象     时的参数传给对象的域。


构造函数和一般函数的区别:

1从功能上的区别:
构造函数是给对象初始化的
一般函数是因为对象需要满足某种功能定义的
2从执行上的区别
构造函数,是对象创建的时候被执行,不用调用。
一般函数是什么时候调用,就什么时候执行,不调用就永远不执行。

构造代码块:
构造代码块。
	作用:给对象进行初始化。
	对象一建立就运行,而且优先于构造函数执行。
	和构造函数的区别:
	构造代码块是给所有对象进行统一初始化,
	而构造函数是给对应的对象初始化。

	构造代码快中定义的是不同对象共性的初始化内容。

	//下面就是构造代码块
	{
		System.out.println("person code run");
		cry();
	}


3:局部代码块:
public void method(){
 {
 int x = 4;
 System.out.println("x="+x);
 }
}
这种写法开发并不常见,但是面试可能会出现,它的作用就是可以限定变量的生命周期.


4:this关键字:
1:Java关键字this只能用于方法方法体内。
2:当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this。
3:this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this,并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this。
简言之:哪个对象调用this所在的函数,this就代表哪个对象。

this关键字的应用:

、函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错.
  、在函数中,需要引用该函数所属类的当前对象时候,直接用this。//比较两个人的年龄
  、注意,如果我们想在一个构造函数中对另一个构造函数进行调用的时候,不能在其构造函数中直接 类名 ( 参数 )这样调用,而是通过this调用另一个构造方法,用法是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。 这叫 this 语句 .
其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的,死记不然容易忘记而且容易搞错,要理解!


//比较两个人的年龄是否相同
class  Demo
{
	public static void main(String[] args) 
	{
		Person p1= new Person(20);
		Person p2= new Person(25);
		boolean b = p1.compare(p2);//比较年龄大小
		System.out.println(b);
	}
}
class Person
{
	private int  age;
	Person(int  age)//构造函数
	{
		
		this.age=age;
	}
	public boolean compare(Person p)
	{

		return this.age==p.age;//this代表的是P1,因为是P1调用了该方法。然后和P2进行比较大小
	}
}

/*
this语句 :用于构造函数之间进行互相调用。
this语句只能定义在构造函数的第一行。因为初始化要先执行。
*/
class  Demo
{
	public static void main(String[] args) 
	{
		//创建对象就用调用Person初始化构造函数
		Person p1= new Person("lisi",20);
		Person p2= new Person("wangwu",25);
	}
}
class Person
{
	private int  age;
	private String name;
	Person()
	{
		System.out.println("你好");
	}
	Person(int  age)
	{		
		this();
		this.age=age;
	}
	Person(String name,int age)
	{
		this(age);//通过this调用
		this.name=name;
	}
}


5:static 关键字:

1,static关键字:
static  是一个修饰符,用于修饰成员(成员变量 、成员方法)
2,当成员被静态修饰后,就多了一种调用方式,除了可以被对象调用外,还可以直接被类名调用
   格式:类名.静态成员
3,static特点
<1>、随着类的加载而加载。  也就是说:静态会随着类的消失而消失,说明它生命周期最长。
<2>、优先于对象存在  。明确一点:静态先存在 对象后存在。
<3> 被所有对象共享 ,
<4> 可以被类名所调用
4、实例变量和类变量的区别:
<1> 存在位置:
   静态变量随着类的加载而存在于方法区中。
   实例变量随着对象的建立而存在于堆内存中。
<2> 生命周期:
        静态变量的生命周期最长,随着类的消失而消失。
        实例变量的生命周期随着对象的消失而消失。
<3>所属不同:
   静态变量也称之为类变量,所属于整个类,被整个类所共享。
   实例变量是对象的特有数据,所属于对象。
5、静态使用注意事项:
<1> 静态方法只能访问静态成员。
           非静态方法既可以访问静态也可以访问非静态
<2> 静态方法中不可以定义this,super关键字。
                因为静态优先于对象存在。所以静态方法中不
                可以出现this。
<3> 主函数是静态的。
6、静态的利弊端:          
利处: <1>对对象的共享数据尽享单独空间的存储,节省空间,没有必要每一个对象都存储一份。
                      <2>可以直接被类名调用。
弊端: <1>生命周期过长。
                     <2>访问出现局限性。(静态虽好,但只能访问静态)


6:主函数
1、定义: 是一个特殊的函数,作为程序入口,可以被jvm调用。
2、涵义:
           public: 代表着该函数的访问权限是最大的。
           static: 代表主函数随着类的加载就已经存在了。
           void: 主函数没有具体的返回值。
           main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
           (String[] args):函数的参数,参数类型是一个数组,该数组的元素是字符串。字符串类型数组。(arguments)
3、主函数是固定格式的 ,被jvm识别

jvm在调用主函数时,传入的是new String[0];这里的0代表的是0个元素


什么使用静态?

要从两方面下手:
因为静态修饰的内容有成员变量和函数。
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成非静态存在于堆内存中。

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

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


静态的应用:工具类

文档注释:
javadoc -d(指定文档存储的位置如果写.代表当前目录,也可以定义一个文件夹)
-author(提取作者内容)
-version(提取版本内容)
javadoc -d 指定的文件目录 -author -version ArrayTool.java

<1> 每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。
<2> 将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象。
   为了更严谨,强制让该类不能建立对象,可以通过将构造函数私有化完成(private)

通过一下代码体现:


/*
静态的应用。

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


虽然可以通过建立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]+"]");
		}
	}
}

/*
一个类中默认会有一个空参数的构造函数,
这个默认的构造函数的权限和所属类一致。
如果类被public修饰,那么默认的构造函数也带public修饰符。
如果类没有被public修饰,那么默认的构造函数,也没有public修饰。

默认构造构造函数的权限是随着的类的变化而变化的。


*/




静态代码块:

静态代码块。
格式:
static
{
	静态代码块中的执行语句。
}

特点:随着类的加载而执行,只执行一次,并优先于主函数。
用于给类进行初始化的。
class StaticCode//代码演示:
{
	int num = 9;
	StaticCode()
	{
		System.out.println("b");
	}
	{
		System.out.println("c"+this.num);//构造代码块,没创建一个对象都调用。调用在静态代码块之后
	}
	static
	{
		System.out.println("a");
	}
	

	StaticCode(int x)
	{
		System.out.println("d");
	}
}

class Demo 
{
	static
	{
		System.out.println("b");//静态代码块只调用一次
	}
	public static void main(String[] args) 
	{
		new StaticCode(4);
		new StaticCode(4);
	}
	static
	{
		System.out.println("c");
	}
}
/*打印结果是
b
c 
a
c9 
d 
c9
d*/






局部代码块,构造代码块,静态代码块
1,局部代码块:
作用:控制变量的生命周期;
在程序中,当我们已经使用完 x 后,并且在接下来的代码中,不会再用到x,那么就没必要让x 在内存中占用空间了,这用情况下,可以使用 局部代码块,将x及其所设计到的区域封装为局部代码块,他们在程序执行中顺序不变,只是在执行完成后消失。
2,构造代码块:
作用:它可以给所有对象进行初始化
存在于:类中。
当类中的构造方法以重载的形式存在时,并且有共同成员变量或共同的方法时,可以通过构造代码块对其进行初始化;这样可以减少代码的重复!
3,静态代码块:
作用:给类进行初始化。
当类中的方法都被静态了化,并且构造方法被private了,这是我们不能,在将这个类实例化,然而又想让类增加一些属性,就可以使用静态代码块


静态代码块和构造代码块:

相同点:都是在JVM加载类时且在构造方法执行之前执     行,在类中都可以定义多个,
    一般在代码块中对一些static变量进行赋值。
不同点:静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。
  静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new一次就执行一次。
  非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行。


/*
Person p = new Person("zhangsan",20);

该句话都做了什么事情?
1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。

*/



7:单例设计模式

单例设计模式:解决一个类在内存只存在一个对象。


想要保证对象唯一。
1,为了避免其他程序过多建立该类对象。先禁止其他程序建立该类对象
2,还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。

这三部怎么用代码体现呢?
1,将构造函数私有化。
2,在类中创建一个本类对象。
3,提供一个方法可以获取到该对象。



对于事物该怎么描述,还怎么描述。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。




/*
这个是先初始化对象。
称为:饿汉式。

Single类一进内存,就已经创建好了对象。
class Single
{
	private static Single s = new Single();
	private Single(){}
	public static Single getInstance()
	{
		return s;
	}
}
*/

//对象是方法被调用时,才初始化,也叫做对象的延时加载。成为:懒汉式。
//Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
	private static Single s = null;
	private Single(){}
	public static Single getInstance()
	{
		if(s==null)
		{
			synchronized(Single.class)//上锁不给多个线程同时进入造成错误

			{				
				if(s==null)
					s = new Single();
			}
		}
		return s;
	}
}

//记录原则:定义单例,建议使用饿汉式。




但是对于第二种懒汉式的单例设计模式,会出现一些小小的问题,当一个线程调用时,是没什么问题的,如果多个线程调用此种方式,那么就会出现问题。

用学生的例子说明单例的用途:
class Student
{
	private int age;

	private static Student s = new Student();
	private Student(){}
	public static Student getStudent()
	{
		return s;
	}

	public void setAge(int age)
	{
		this.age = age;
	}
	public int getAge()
	{
		return age;
	}
}
class SingleDemo 
{
	public static void main(String[] args) 
	{
		Student s1 = Student.getStudent();
		Student s2 = Student.getStudent();

		s1.setAge(23);//判断单例是不是只有一个对象

		System.out.println(s2.getAge());
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值