Day05 06 面向对象

Day05 06 面向对象

——类与对象、成员变量和局部变量、匿名对象、封装、构造函数、构造代码块
this、static、静态、对象初始化和调用、单例设计模式

3.1 面向对象概念

3.1.1 理解面向对象
面向对象是相对面向过程而言
面向对象和面向过程都是一种思想
面向过程:强调的是功能行为
面向对象:将功能封装进对象,强调具备了功能的对象。
面向对象是基于面向过程的。
在这里插入图片描述
面试问题:什么是面向对象:1.面向对象的特点 能让复杂问题简单化,能让我们的角色转变,从执行者变为指挥者 2.举具体例子,结合实际场景:面试官就是在用面向对象的方法思考问题,公司现在有找人需求是因为用户量现在比较大,代表公司现在蒸蒸日上发展。你用面向对象的方式思考问题,你需要找一些具备专业编程经验的人来完成公司的工作,那我就是那个对象,我具备专业变成的功能,你找我就对了。其实你就是在指挥我做事情,你在使用我的专业编程功能为公司创造价值。当然,我不仅具备专业编程需求,还具备表达能力、处理人际关系能力等。
人开门:名词提炼法。

{
开门(门)
{
门.开();
}
}

{
开()(操作门轴等。)
}
3.1.2 面向对象的特点
面向对象:三个特征:封装,继承,多态。
以后开发:其实就是找对象使用,没有对象,就创建一个对象。
找对象,建立对象,使用对象,维护对象。

3.2 类与对象的关系

类和对象的关系:

显示生活中的对象:张三 李四
想要描述:提取对象中共性内容,对具体的抽象。
描述时:这些对象的共性有:姓名、年龄、性别、学习java功能。

映射到java中,描述就是class定义的类。
具体对象就是对应java在堆内存中用new建立的实体(实体中存放多个数据)。

类:对现实生活中事物的描述。
对象:这类事物,实实在在存在个体。
在这里插入图片描述
//需求:描述汽车(颜色,轮胎数)。描述事物其实就是在描述事物的属性和行为。
//属性对应的是类中的变量,行为对应的是类中的函数(方法)。其实定义类,就是在描述事物,就是在定义属性和行为。属性和行为又共同成为类中的成员(成员变量和成员方法)。

在这里插入图片描述

class Car
{
	//描述颜色
	String color = "红色";//默认值为null ,红色为显示初始化值
	//描述轮胎数
	int num = 4;

	//运行行为
	void run()
	{
	System.out.println(color + ".." + num);
	}
	
}

class  CarDemo
{
	public static void main(String[] args) 
	{
		//生产汽车,在java中通过new 操作符来完成。其实就是在堆内存产生一个实体。、
		Car c = new Car();//c 就是一个类类型变量。记住:类类型变量指向对象。

		//需求:将已有车的颜色改为蓝色,指挥该对象做使用。在java中指挥方式是:对象.对象成员
		c.color = "blue";
		
		c.run();//输出已改变后的值,blue..4
		
		Car c1 = new Car();
		c1.run();//red..a
	}
}

多个引用指向同一个对象
在这里插入图片描述
成员变量和局部变量
作用范围:成员变量作用于整个类中。局部变量作用于函数中,或者语句中。
在内存中位置:成员变量在堆内存中,因为在内存中存在。局部变量:存在栈内存中。
成员变量都有默认值,成员变量定义完后不赋值可以直接参与运算,因为有默认初始化值,因为在堆内存中。局部变量不初始化不可能参与运算,因为在栈内存中必须要有初始化值以后才能参与运算。
匿名对象
匿名对象是对象的简化形式。
匿名对象两种使用情况:当对对象方法仅进行一次调用的时候,匿名对象可以作为实际参数进行传递
Car c = new Car();
c.num = 5;
–>这两句话可以简写为一句话:
new Car().num = 5;
new Car().color = “blue”;
new.Car().run();
匿名对象与有名对象区别:
在这里插入图片描述
匿名对象调用属性没有意义,改变完就没有意义了。可以调用方法,方法里有内容。
Car c = new Car();
c.run();//如果再调用c.num = 4;就有区别
–>new Car().run();这一句与上两句话没有区别。
匿名对象使用方法一:当对对象的方法之调用一次时,可以用匿名对象来完成,这样写比较简化。如果对一个对象进行多个成员调用,必须给这个对象起名字。
匿名对象使用方法二:可以将匿名对象作为实际参数进行传递。
//需求:汽车修配厂。对汽车进行改装,将来的车都改成黑色,三个轮胎。
在这里插入图片描述

public static void main(String[] args) 
	{
		//Car c = new Car();
		//show(q);
		show(new Car());
	}
	public static void show(Car c)
	{
		c.num = 3;
		c.color = "black";
		c.run();
	}

在这里插入图片描述
此处的show方法在执行完之后就释放变成垃圾,没有用了。

3.3 封装(Encapsulation)

封装:是指隐藏对象的属性和现实细节,仅对外提供公共访问方式。
好处:将变化隔离。便于使用。提高重用性。提高安全性。
封装原则:将不需要对外提供的内容都隐藏起来。把属性都封装,提供公共方法对其访问。
封装private
private:私有,权限修饰符:用于修饰类中的成员(成员变量,成员函数)。私有只在本类中有效。
将age私有化以后,类以外即使建立了对象也不能直接访问。
但是人应该有年龄,就需要在Person类中提供对应访问age的方式。
注意:私有仅仅是封装的一种表现形式。隐藏的最低权限是private。
之所以对外提供访问方式,就是因为可以在访问方式中加入逻辑判断语句。对访问的数据进行操作,提高代码的健壮性。

class Person
{
	private int age;

	public void setAge (int a)
	{
		if(a > 0 && a < 130 )
		{
			age = a;
			speak();
		}
		else 
			System.out.println("nono");
	}
	
	public int getAge()
	{
		return age;
	}

	void speak()
	{
		System.out.println("age = " + age);
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		Person p = new Person();
		//p.age = 20;
		p.setAge(20);
		//p.speak();//-->打印默认值为0
	}	
}

把a = 40赋值给堆内存中对象中的age,变化的都是对象中的age,p指向的是对应的实体。
在这里插入图片描述

3.4 构造函数

特点:1.函数名和类名相同 2.不用定义返回值类型 3. 不可以写return语句
作用:给对象进行初始化。
注意:1. 默认构造函数的特点。2. 多个构造函数是以重载的形式存在的。
对象一建立,就会调用与之对应的构造函数。
构造函数的作用:可以用于给对象进行初始化。
构造函数小细节:当一个类中没有定义构造函数时,那么系统就会默认给该类加入一个空参数的构造函数。当在该类中自定义了构造函数后,默认的构造函数就没有了。

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

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

class Person
{
	//Person(){};-->系统默认给该类加入的空参数
	Person()
	{
		System.out.println("person run");
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		Person p = new Person();//-->person run
		new Person();//-->person run
	}
}

class Person
{
	private String name;
	private int age;
	/*
	构造代码块 
	作用:给对象进行初始化。对象一建立就运行,而且优先于构造函数执行。
	和构造函数区别:构造代码块是给所有对象进行统一初始化。而构造函数是给对应的对象初始化。
	构造代码块中定义的是不同对象共性的初始化内容。
	*/
	{
		System.out.println("person code run");
		cry();//-->把不同对象的共性的初始化方式定义在构造代码块中
	}
	Person()
	{
		System.out.println("A:name = " + name + ",age = " + age);
		//cry();
	}
	Person(String n)
	{
		name = n;
		System.out.println("B:name = " + name + ",age = " + age);
		//cry();
	}
	Person(String n,int a)
	{
		name = n;
		age = a;
		System.out.println("C:name = " + name + ",age = " + age);
		//System.out.println("cry");
		//cry();
	}
	public void setName(String n)
	{
		name = n;
	}
	public String getName(String n)
	{
		return name;
	}
	public void cry()
	{
		System.out.println("cry");
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		Person p1 = new Person();
		p1.cry();
		
		Person p2 = new Person("list");//-->构造函数只能执行一次
		p2.setName("liss");//-->一般方法可以执行多次
		p2.setName("lisskk");
		System.out.println(p2.getName());

		Person p3 = new Person("wangwu",10);
	}
}

3.5 this关键字

this:看上去,是用于区分局部变量和成员变量同名的情况。
this为什么可以解决这个问题
this到底代表什么:代表本类的对象,到底代表哪一个?this代表它所在函数所属对象的引用。
简单说:哪个对象在调用this所在的函数,this就代表哪个对象。
this应用:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。但凡本类功能内部使用了本类功能对象,都用this表示。


class Person
{
	private String name;
	private int age;

	Person(int age)
	{
		rhis.age = age;
	}
	Person(String name)
	{
		//name = name;
		/*没有把lisi赋值给对象在堆内存中,出现局部变量名称和成员变量名称相同
		结果:name = null,age = 0;
		如果局部中定义过一个name,则这两个都是局部的name,局部中有就在局部中找name使用
		局部变量中没有才去找成员变量
		*/
		this.name = name;
	}
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public void speak()
	{
		System.out.println("name = " + this.name + ",age = " + this.age);//-->也可以省略
		//this.show();-->在同一类中this可以省略
		show();
	}
	publid void show()
	{
		System.out.prinrln(this.name);
	}
	//需求:给人定义一个用于比较年龄是否相同的功能,也就是是否是同龄人。
	public boolean compare(int age)
	{
		return this.age == p.age;
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		//Person p = new Person("list");
		Persin p1 = new Person(20);
		Persin p2 = new Person(25);
		boolean b = p1.compare(p2);
		System.out.println(b);
	}
}

this 关键字在构造函数间的调用。
this语句只能定义在构造函数的第一行。因为我初始化要先执行。


class Person
{
	private String name;
	private int age;

	Person(String name)
	{
		this.name = name;
	}
	Person(String name,int age)
	{
		//this.name = name;
		//Person(name);-->一般函数调用思想,构造函数间相互调用不能这样写
		this(name);//p(name);
		this.age = age;
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		Person p = new Person("lisi",30);
		
	}
}

3.6 static(静态)关键字

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

被修饰后的成员具备以下特点:
随着类的加载而加载。也就是说:静态会随着类的消失而消失。说明它的生命周期最长;
优先于对象存在。明确一点:静态是先存在的,对象是后存在的;
被所有对象所共享;
可以直接被类名调用(类名.对象成员)

实例变量和类变量的区别:
1.存放位置。类变量随着类的加载而存在于方法区中。实例变量随着对象的建立而存在于堆内存中。
2.生命周期。类变量生命周期最长,随着类的消失而消失。实例变量生命周期随着对象的消失而消失。

注意使用:
1.静态方法只能访问静态成员(静态方法和静态变量)。非静态方法既可以访问静态页可以访问非静态;
2.静态中方法不可以写this,super关键字。因为静态优先于对象存在,所以静态方法中不可以出现this;
3.主函数是静态的

静态有利有弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中存储一份。可以直接被类名调用。
弊端:生命周期过长。访问出现局限性。(静态虽好,只能访问静态。)

class Person
{
	String name;//成员变量,实例变量(对象的变量)
	static String country = "CN";//静态的成员变量,类变量。
	public static void show()
	{
		System.out.prin!tln(name + ":" );
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		//Person p = new Person();
		//p.name = "zhangsan";
		//p.show();

		//System.out.println(p.country);

		Person.show();
	}
}

在这里插入图片描述
main函数
public static void main(String[] args){}–>虚拟机要的主函数只有这个,别的都是重载。
主函数:是一个特殊的函数。作为程序的入口,可以被jvm(虚拟机)调用。
主函数定义:
public:代表着该函数访问权限是最大的。
static:代表主函数随着累的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被jvm识别。、
(String[] arr):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组(存储字符串类型元素的数组)。
主函数固定格式的:jvm识别。
jvm在调用主函数时,传入的是new String[0];(0个元素)


class MainText
{
	public static void main(String[] args)//new String[] ;只能接收两种,空和数组int[] arr = null;int[] arr = new int[2];
	{
	//System.out.println(args.length);
	//System.out.println(args);//args[0]-->脚标越界,0脚标代表第一个元素
	for(int x = 0; x<args.lengrh;x++)
		System.out.println(args[x]);
	}
}
class MainDemo
{
	public static void main(String[] args)
	{
		String[] arr = {"ha","haha","xi","xixix"};
		MainTest.msin(arr);
	}
}

主函数传值,怎样往args[]里传参数:javac 启动了编译器,java对外提供功能,对应底层的虚拟机,虚拟机执行了MainDemo这个类,这个类中的方法被虚拟机调用。启用虚拟机在调用类的同时再往里传一些参数。虚拟机将类后面跟的3个数据用空格隔开,自动存入到长度为3的数组当中,并把haha hehe heihei作为0 1 2三个脚标的元素存储进去。
在这里插入图片描述
什么时候使用静态
要从两方面下手:因为静态修饰的内容有成员变量和函数。
什么时候定义静态变量(类变量)呢?当对象中出现共享数据时,该数据被静态所修饰。对象中的特有数据要定义成非静态存在于堆内存中。

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

class Person
{
	String name;
	public static void show()
	{
		System.out.println("haha");
		System.out.println(name + "haha");//访问到对象中的数据,此时前面不能加static
	}
}

class PersonDeom 
{
	public static void main(String[] args) 
	{
		//Person p = new Person();
		//p.show();//show功能没有访问过name属性,改为静态的,这个功能没有必要使用对象
		Person.show();//只想显示一下
	}
}

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

虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。发现了问题。
1.对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
2.操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
这时就要考虑,让程序更严谨,是不需要对象的。可以将ArrayTool中的方法都定义成static的,直接通过类名调用即可。

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

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[] arr = {3,4,1,8};

		int max = 0;
		for(int x = 1; x < arr.length; x++)
		{
			if(arr[x] > arr[max])
				max = x;
		}
		return arr[max];
	}

}
//多个应用程序中,不同java文件中拥有相同功能求最大值,把这个功能单独抽离出来
//把操作数组的常用功能单独封装在一个类当中,这个类想什么时候用就什么时候用
//全部封装在一个对象中,找到了对象就找到了功能
class Test
{
	public static int getMax(int[] arr)
	{
		int[] arr = {3,4,1,8};

		int max = 0;
		for(int x = 1; x < arr.length; x++)
		{
			if(arr[x] > arr[max])
				max = x;
		}
		return arr[max];
	}
}

编译方式1:
在这里插入图片描述
编译方式2:javac ArrayToolDemo.java–>出现ArrayTool.class和ArrayToolDemo.class
当编译ArrayToolDemo.java文件用到其他类,他会在指定目录(set class path)/当前目录下找有没有ArrayTool.class文件,如果当前目录下没有ArrayTool.class文件的话,会找当前文件有没有ArrayTool.java,如果有加先找java文件编译了再编译自己

//ArrayToolDemo.java
class  ArrayToolDemo
{
	public static void main(String[] args) 
	{
		int[] arr = {3,5,9,7,65,9,6,8};
		ArrayTool.Max(arr);
		System.out.println("max = " + max);
		/*
		ArryTool tool = new ArryTool();
		
		int max = tool.getMax(arr);
		System.out.println("max = " + max);

		int max = tool.getMax(arr);
		System.out.println("max = " + max);

		tool.printArray(arr);
		tool.selectSort(arr);
		tool.printArray(arr);
		*/
	}
}

// ArrayTool.java
/**
对类的描述
这是一个可以对数组进行操作的工具类,该类中提供了获取最值、排序等功能。
@author 张三(作者)
@version V1.1(版本)
*/
public class ArrayTool
{
	/**
	空参数构造函数。
	*/
	//private ArrayTool(){}
	/**
	凡是public修饰符的功能都用文档注释描述,都可以被文档注释工具所提取
	获取一个整型数组中的最大值。
	@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 a 要置换的位置。
	@param b 要置换的位置。
	*/
	private static void swap(int[] arr,int a,int b)//排序,没有必要提供程序,私有化,能隐藏起来的全部隐藏
	{
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}
	/**
	用于打印数组中的元素,打印形式:[element1,element2,...]
	*/
	public static void printArray(int [] arr)
	{
		System.out.println("[");
		for(int x = 0; x<arr.length; x++)
		{
			if(x != arr.length-1)
				System.out.println("arr[x] + ",");
			else
				System.out.println("arr[x] + "]");
		}
	}

帮助文档的制作javadoc
在这里插入图片描述
set classpath = .;c:\myclass–>"."先找当前路径,再找指定路径

接下来,将ArryTool.class文件发送给其他人,其他人只要将该文件设置到classpath路径下,就可以使用该工具类。但是,很遗憾,该类中到底定义了多少个方法,对方却不清楚,因为该类并没有使用说明书。开始制作程序的说明书。java说明书通过文档注释来完成。
javadoc -d myhelp如果当前目录下没有这个文件夹,会帮你自动建一个
javadoc -d myhelp -author -version取里面的作者和版本
在这里插入图片描述
如果要给一个类生成帮助文档的话,必须要用public修饰
public class ArryText

一个类中默认会有一个空参数的构造函数,系统自己加入的。这个默认的构造函数的权限和所属类一致,如果类被public被修饰,那么默认的构造函数也带public修饰符。如果类没有被public修饰,那么默认的构造函数也没有public修饰。默认构造函数的权限是随着类的变化而变化的。
class Demo
{
Demo(){}//自定义构造函数,不是默认构造函数
//不写就是默认的,写上了默认的就没有了
}
静态代码块
格式:
static
{
静态代码块中的执行语句。
}
特点:随着类的加载而执行,只执行一次。用于给类惊醒初始化。并优先于主函数。

class StaticCode 
{
	static
	{
		System.out.println("a");
	}
}
class StaticCodeDemo
{
	static
	{
		System.out.println("b");
	}

	public static void main(String[] args) 
	{
		new StaticCode();
		new StaticCode();
		System.out.println("over");
	}
	static
	{
		System.out.println("b");
	}
}

D:>java0217>java StaticCodeDemo
b c a over
在这里插入图片描述
先加载类,让类先进来,此时没有对象
在这里插入图片描述
StaticCode s = null;//这个变量没有任何实体指向,存在没有任何意义,此时类没有加载到内存空间中
s = new StaticCode();
StaticCode.show();
下面这两种情况加载了,用到了类中的内容的时候,类才会被加载。
用到类中的内容时才加载,只引用不加载。类到底加没加载,通过静态模块验证。

class StaticCode 
{
	StaticCode()
	{
		System.out.println("b");
	}
	static
	{
		System.out.println("a");//静态代码块给类初始化
	}
	{
		System.out.println("c");//构造代码块给对象初始化
	}
	StaticCode(int x)
	{
		System.out.println("d");//构造函数给对应对象初始化
	}
	public static void show()
	{
		System.out.println("show run");
	}
}
class StaticCodeDemo
{
	static
	{
		//System.out.println("b");
	}

	public static void main(String[] args) 
	{
		new StaticCode(4);//a c d 不会出现b,执行的是参数的初始化动作
	}
	static
	{
		//System.out.println("b");
	}
}

在这里插入图片描述
在这里插入图片描述
num是非静态成员,需要this.,静态里不能写this,所以访问不了
在方法中定义使用的this关键字,它的值是当前对象的引用.也就是说你只能用它来调用属于当前对象的方法或者使用this处理方法中成员变量和局部变量重名的情况.
而且,更为重要的是this和super都无法出现在static 修饰的方法中,static 修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象.如果使用的是类来调用而不是对象,则 this就无法指向合适的对象.所以static 修饰的方法中不能使用this.
在这里插入图片描述
构造代码块给对象初始化
对象的初始化过程
对象建立过程:Person p = new Person();
1.在栈内存中有个引用,右边有值,加载Person类。
new对象的时候会将Person.class文件从硬盘当中通过java的虚拟机将Person.class文件加载进内存并开辟堆内存空间。
2.静态代码块被执行。(静态优先于对象)
3.空间开辟

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

class Person 
{
	private String name = "haha";//-->在构造代码块前
	private int age;
	private static String country = "cn";
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	{
		System.out.println(name + ".." + age );//构造代码块
	}
		public void setName(String name)
		{
			this.name = name;
		}
		public void speak()
		{
			System.out.println(this.name + "..." + this.age);
		}
		public static void showCountry()
		{
			System.out.print("country = " + country);
			Person.method();
			//在showCountry()中调用method,或者在method()中调用shoeCountry()。成员在被调用时可以用,不能用this,因为是静态(省略  类名.)
		}
		public static void method()
		{
			System.out.println("method run");
		}
}
class PersonDemo
{
	public static void main(String[] args) 
	{
		Person p = new Person("zhangsan",20);
		p.setName("lisi");
	}
}

对象调用成员过程
非静态方法调用过程
在这里插入图片描述
静态方法调用过程
showCountry调用后,开辟的空间中没有this,直接所属类Person,不需要堆内存,因为静态方法堆内存不访问,走的都是静态区域里的数据,与对象无关。
在这里插入图片描述

3.7 单例设计模式

单例模式方式一:饿汉式
设计模式:解决某一类问题中最行之有效的方法。java中有23种设计模式。
单例设计模式:解决一个类中在内存中只存在一个对象。
想要保证对象唯一:
1.为了避免其他程序过多建立该类对象,先禁止其他承诺工序建立该类对象。
2.还为了让其他程序可以访问该类对象,只好在本类中自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三步怎么用代码体现?
1.将构造函数私有化。
2.在类中创建一个本类对象。
3.提供一个方法可以获取该对象。
对于事物该怎么描述还怎么描述。当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
饿汉式

class Single
{
	private Single(){}//私有化构造函数

	private static Single s = new Single();
	//创建本类对象,静态方法访问静态变量,s为成员变量,类中的变量,要私有化

	public static Single getInstance()
	//对外提供共有的方法返回对象 instance实例
	//只有一个对象,只需要get不需要set
	{
		return s;
	}
}

class SingleDemo
{
	public static void main(String[] args) 
	{
		Single ss = Single.getInstance();
		//方法被调用:对象调用(不能new)、类名调用(静态方法,访问静态成员)
	}
}

class Single
{
	private int num;
	public void setNum(int num)
	{
		this.num = num;
	}
	public int getNum()
	{
		return num;
	}
	
	Single(){}//私有化构造函数

	private static Single s = new Single();
	//创建本类对象,静态方法访问静态变量,s为成员变量,类中的变量,要私有化

	public static Single getInstance()
	//对外提供共有的方法返回对象 instance实例
	//只有一个对象,只需要get不需要set
	{
		return s;
	}
}

class SingleDemo
{
	public static void main(String[] args) 
	{
		Single s1 = new Single();
		Single s2 = new Single();
		s1.setNum(30);
		System.out.println(s2.getNum());
		//有两个对象,给第一个对象赋值30,与第二个对象无关	
	}
}

在这里插入图片描述
如想保证类的唯一性

class Single
{
	private int num;
	public void setNum(int num)
	{
		this.num = num;
	}
	public int getNum()
	{
		return num;
	}
	
	private Single(){}//私有化构造函数

	private static Single s = new Single();
		//创建本类对象,静态方法访问静态变量,s为成员变量,类中的变量,要私有化

	public static Single getInstance()
	//对外提供共有的方法返回对象 instance实例
	//只有一个对象,只需要get不需要set
	{
		return s;
	}
}

class SingleDemo
{
	public static void main(String[] args) 
	{
		Single s1 = Single.getInstance();
		Single s2 = Single.getInstance();
		s1.setNum(23);
		System.out.println(s2.getNum());
		//内存中只有一个对象,有三个引用在指向 s1 s2 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 Age()
	{
		return age;
	}
}

之前:创立两个不同对象
Student s1 = Stedent.getStudent();
s1.setAge(30);
Student s2 = Stedent.getStudent();
s2.setAge(26);
现在:两个表示同一个对象
Studen s1 = Student.getStudent();
Studen s2 = Student.getStudent();
单例模式方式二:懒汉式
在这里插入图片描述

/*
这个是先初始化对象。称为:饿汉式。|一般开发用这个。|
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();
	//public static synchronized Single getInstance();	
	//synchronized 同步的,每次都需判断是否同步会降低代码效率
	{
		//if(s == null)
			//s = new Single();
		//return s;
		
		if (s == null)//通过双重判断
		{
			synchronized(Single.class)
			{
				if(s == null)
					s = new Single();
			}
			return s;
		}
	}
}
class SingleDemo
{
	public static void main(String[] args) 
	{
		Single s1 = Single.getInstance();
		Single s2 = Single.getInstance();
		s1.setNum(23);
		System.out.println(s2.getNum());
		//内存中只有一个对象,有三个引用在指向 s1 s2 s
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值