黑马程序员——Java基础—面向对象(一)
2015-04-02 19:56
183 查看
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一理解面向对象
二面向对象的特征
三类与对象的关系
四类的定义
五成员变量和局部变量的不同
六匿名对象
七封装
八构造方法
九构造代码块
十this关键字
十一static关键字
十二对象的初始化过程
十三设计模式之单例设计模式
面向对象(一)
在使用面向对象概念的时候:
1.先找具有所需要功能的对象是否存在,存在即可使用;
2.如果不存在,那么创建一个具备所需功能的对象;
3.创建具备不用功能对象的过程,就是简化开发,提高代码复用性的过程
2.继承:Java的继承特性,能使一个派生类类拥有其父类的属性和方法,并扩展其特有的方法;
3.多态:指允许不同类的对象对同一方法做出不同响应。即同一方法可以根据调用对象的不同而表现出多种不同的行为方式。多态的发生必须满足1)继承;2)复写;3)父类引用指向子类对象;这三个条件
![](http://img.blog.csdn.net/20150402195131888)
属性:就是类中声明的成员变量;
行为:就是类中声明的成员方法;
定义一个类,其实就是在定义类中的成员变量和成员方法。
类的示例代码:
创建对象的代码示例:
该对象的内存结构图如下:
![](http://img.blog.csdn.net/20150402195134402)
当
1.在堆内存中开辟空间,储存
2.将内存地址赋给栈内存中该对象的引用
3.
1)成员变量作用域为整个类;
2)局部变量作用域为方法或者语句
2.在内存中的位置不同:
1)成员变量在堆内存中;对象实例被new出来之后,才开辟内存空间给成员变量;
2)局部变量在栈内存中
如果使用多个匿名对象,第一行执行完之后,由于没有引用指向这个对象,该对象立刻成为垃圾,等待回收。
![](http://img.blog.csdn.net/20150402195217256)
用匿名对象调用方法是通常做法,调用成员属性没有意义。所以,当对对象方法只调用一次时,可以用匿名对象完成。如果对对象进行多个成员调用,必须给这个对象起名字。
2.应用二:
将匿名对象作为实际参数进行传递。
不使用匿名对象作为参数的示例代码:
上述代码内存运行过程如图:
![](http://img.blog.csdn.net/20150402195248128)
运行过程:
1.将创建的对象的内存地址赋给引用
2.将引用
3.
使用匿名对象作为参数的示例代码:
上述代码内存运行过程如图:
![](http://img.blog.csdn.net/20150402195548056)
使用匿名对象作为参数,直接将对象地址赋给
封装是指,隐藏对象的属性和实现细节,仅对外提供公共访问方式。
2.封装的好处
1)类的内部变化被隔离,调用者无须知道这些变化,照样能实现功能;
2)类内部细节的实现无须调用者了解,便于使用;
3)封装的代码可以被不同调用者使用,提高复用性;
4)不想对外开放的属性,通过封装能很好隐藏起来,提高安全性
3.private关键字
示例代码:
1)方法名与类名相同;
2)不用定义返回值类型;
3)不可以写
4)在创建对象的时候,自动调用
2.构造方法的作用
构造方法可以对对象进行初始化。对象在创建的时候,就应该具备其基本特性。构造方法就初始化了这些基本特性。
3.构造方法小细节
1)当一个类中没有定义构造方法时,Java默认会为该类加入一个空参数的构造方法;
2)当在类中声明了自定义的构造方法后,Java不再为该类添加构造方法;
3)对象创建时就具备的特性和行为,可以定义在构造函方法中,以便创建时初始化;
4)构造方法中初始化过了的私有变量,还是需要定义
示例代码:
构造代码块是定义在类中的一个独立代码区间。构造代码块的作用是为对象进行初始化。对象一旦创建就立刻运行构造代码块,且运行优先级高于该类的构造方法。
2.构造代码和构造方法的区别
1)构造代码是给所有对象进行统一初始化;
2)构造方法是给对应的对象初始化
3.构造代码块的应用
将所有对象的共性属性或行为定义在构造代码块中,那么所有对象创建的时候同一执行构造代码块中的内容。
示例代码:
2.this关键字的应用
1)
示例代码:
2)this关键字可以用于构造方法间互相调用
示例代码:
3)注意:
上述代码中,country被声明成静态变量,则该变量不再存在于堆内存中,而作为共享数据储存于方法区,如下图:
![](http://img.blog.csdn.net/20150402195635483)
2.static关键字的特点
1)随着类的加载而加载
类一旦加载到内存,
2)优先于对象存在
静态随着类的加载而存在,对象创建后才存在
3)被所有对象共享
所有对象共享一份静态成员
4)可以直接被类名所调用
由于类刚加载的时候,还没有对象,而静态成员已经加载到内存,所以可以用类名直接调用
3.静态变量和成员变量的区别
1)存放位置不同
静态变量随着类的加载而存在与方法区中
成员变量随着对象的创建而存在于堆内存中
2)生命周期不同
静态变量生命周期等于类的生命周期,随着类存在消亡
成员变量生命周期随着对象存在消亡,生命周期较静态变量短
4.static关键字注意事项
不能把所有成员都定义成
1)不是所有成员都能被所有对象共享;
2)定义成
3)静态方法中不能引用非静态成员,即静态方法只能访问静态成员(非静态方法可以访问静态成员);
4)静态方法中不能出现
5.静态的利弊
利:
1)存储所有对象共享的成员于方法区,节省资源;
2)可以直接被类名调用,使用简单
弊:
1)生命周期过长,可能出现浪费资源的情况;
2)访问出现局限性(静态方法只能访问静态成员)
6.使用static关键字的时机
1)当对象中出现需要共享的数据时,使用
2)当成员方法没有对类中任何非静态成员变量进行操作的时候,该方法可以定义成静态成员方法
7.静态的应用
定义了
示例代码:
8.静态代码块
1)格式
2)特点
随着类的加载而执行,并且只执行一次。用于对类进行初始化。
示例代码:
上述代码的输出结果为:a c d
执行过程为:
1> 先执行
2> 后执行构造代码块,由于其要初始化对象,优先级介于构造方法和静态代码块间,输出
3> 最后执行相应的构造方法,输出
注意:
静态代码块中不能访问非静态成员变量,构造代码块可以访问非静态变量。
示例代码:
输出:c9
9.主函数的属性
主函数的定义:
主函数是一个特殊函数,作为程序的入口,被jvm调用。主函数格式固定。
public:主函数无访问限制
static:主函数为静态,随着类的加载就存在于方法区
void:主函数没有返回值
mian:不是关键字,是能被jvm识别的特殊标识符
String[] args:函数的参数,参数类型为字符串数组
![](http://img.blog.csdn.net/20150402195712283)
1)通过虚拟机,加载类的
2)执行方法区静态代码块(如有),对类进行初始化;
3)在堆内存中开辟对象
4)对类成员变量进行显式初始化(如有);
5)执行构造代码块(如有),对对象进行初始化;
6)执行构造方法,调用相应的构造方法对成员变量进行初始化;
7)将内存地址赋给栈内存中该对象的引用
2.对象调用非静态成员方法过程
1)从方法区将要调用的非静态方法加载到栈内存;
2)将该对象的引用的内存地址,赋给要调用的方法中自带的this关键字,此时,this指代的就是该对象的引用;
3)内存地址赋值完毕,this指向该对象,将栈内存中变量的值,赋给堆内存中对象的成员变量,完成赋值,结束对非静态方法的调用
想要保证对象唯一性:
1.禁止其他程序建立该类的对象;
2.在该类中自定义一个对象;
3.开放端口,让其他程序访问该对象
实现:
1.私有化构造方法;
2.在该类中创建一个本来对象;
3.提供方法获取该对象
饿汉式:
单例模式内存图:
![](http://img.blog.csdn.net/20150402195757149)
图示说明:
1.
2.
3.由于
懒汉式:
饿汉式和懒汉式的不同:
饿汉式:
懒汉式:
开发时,用饿汉式
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
一理解面向对象
二面向对象的特征
三类与对象的关系
四类的定义
五成员变量和局部变量的不同
六匿名对象
七封装
八构造方法
九构造代码块
十this关键字
十一static关键字
十二对象的初始化过程
十三设计模式之单例设计模式
面向对象(一)
一、理解面向对象
面向对象作为一种编程思想,其本质是基于面向过程的。相对于强调功能行为的面向过程变成方式而言,面向对象强调的是功能的封装,形成具备一定功能的对象。面向对象的思维方式,符合人们的思考习惯,可以将复杂的事情简单化。从面向过程到面向对象,程序员完成了从执行者到指挥者的角色转变。在使用面向对象概念的时候:
1.先找具有所需要功能的对象是否存在,存在即可使用;
2.如果不存在,那么创建一个具备所需功能的对象;
3.创建具备不用功能对象的过程,就是简化开发,提高代码复用性的过程
二、面向对象的特征:
1.封装:Java的封装是一种信息隐藏技术,将属性和方法封装在一个类当中,只对调用者开放相应接口来访问该类的成员属性和方法。封装提高了程序的复用性和可维护性;2.继承:Java的继承特性,能使一个派生类类拥有其父类的属性和方法,并扩展其特有的方法;
3.多态:指允许不同类的对象对同一方法做出不同响应。即同一方法可以根据调用对象的不同而表现出多种不同的行为方式。多态的发生必须满足1)继承;2)复写;3)父类引用指向子类对象;这三个条件
三、类与对象的关系
Java中通过定义类的形式,来描述生活中的具体事物。类是具体事物的抽象定义。对象则是该类在生活中的具体体现,是实实在在的个体。四、类的定义
生活中描述事物,就是要描述事物的不同属性和行为。如:人有身高,体重,年龄等属性;有起床,刷牙等行为。在Java中,用类(class)来描述事物。
属性:就是类中声明的成员变量;
行为:就是类中声明的成员方法;
定义一个类,其实就是在定义类中的成员变量和成员方法。
类的示例代码:
class Car { String color = "red"; int num = 4; public void run() { System.out.println("Running..."); } }
创建对象的代码示例:
class Test { public static void main(String[] args) { Car c1 = new Car(); c1.color = "blue"; Car c2 = new Car(); } }
该对象的内存结构图如下:
当
new一个
Car对象的时候:
1.在堆内存中开辟空间,储存
Car()对象及其成员变量
color,
num;
2.将内存地址赋给栈内存中该对象的引用
c1,
c1即指向
Car()对象;
3.
c1修改
color的值,将新值赋给
color
五、成员变量和局部变量的不同
1.作用域不同:1)成员变量作用域为整个类;
2)局部变量作用域为方法或者语句
2.在内存中的位置不同:
1)成员变量在堆内存中;对象实例被new出来之后,才开辟内存空间给成员变量;
2)局部变量在栈内存中
六、匿名对象:
1.应用一:new Car().num = 5; new Car().color = "green"; new Car().run();
如果使用多个匿名对象,第一行执行完之后,由于没有引用指向这个对象,该对象立刻成为垃圾,等待回收。
用匿名对象调用方法是通常做法,调用成员属性没有意义。所以,当对对象方法只调用一次时,可以用匿名对象完成。如果对对象进行多个成员调用,必须给这个对象起名字。
2.应用二:
将匿名对象作为实际参数进行传递。
不使用匿名对象作为参数的示例代码:
class Test { public static void main(String[] args) { Car c = new Car(); show(c); } public static void show(Car c) { c.num = 3; c.color = "black"; c.run(); } }
上述代码内存运行过程如图:
运行过程:
1.将创建的对象的内存地址赋给引用
c,
c即指向该对象;
2.将引用
c传给该对象的
show()方法,即将该对象的地址赋给
show()方法的参数
c,
show()方法中的参数
c即指向该对象;
3.
show()方法访问该对象的成员变量
使用匿名对象作为参数的示例代码:
public static void main(String[] args) { show(new Car()); } public static void show(Car c) { c.num = 3; c.color = "black"; c.run(); }
上述代码内存运行过程如图:
使用匿名对象作为参数,直接将对象地址赋给
show()方法的参数
c,
c再访问该对象的成员变量。
七、封装
1.定义封装是指,隐藏对象的属性和实现细节,仅对外提供公共访问方式。
2.封装的好处
1)类的内部变化被隔离,调用者无须知道这些变化,照样能实现功能;
2)类内部细节的实现无须调用者了解,便于使用;
3)封装的代码可以被不同调用者使用,提高复用性;
4)不想对外开放的属性,通过封装能很好隐藏起来,提高安全性
3.private关键字
private:用于修饰类中的成员变量和成员方法,被修饰的成员只能在本类被访问。
private是封装的一种表现形式。当使用
private修饰成员变量后,应设置相应的
get和
set方法,让外部访问私有变量。
示例代码:
class Person { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void getName() { return name; } public void getAge() { return age; } }
八、构造方法
1.构造方法特点1)方法名与类名相同;
2)不用定义返回值类型;
3)不可以写
return语句;
4)在创建对象的时候,自动调用
2.构造方法的作用
构造方法可以对对象进行初始化。对象在创建的时候,就应该具备其基本特性。构造方法就初始化了这些基本特性。
3.构造方法小细节
1)当一个类中没有定义构造方法时,Java默认会为该类加入一个空参数的构造方法;
2)当在类中声明了自定义的构造方法后,Java不再为该类添加构造方法;
3)对象创建时就具备的特性和行为,可以定义在构造函方法中,以便创建时初始化;
4)构造方法中初始化过了的私有变量,还是需要定义
set和
get方法,因为在对象的使用过程中,可能涉及改变其私有变量的值,此时就要用到
set方法,获取该私有变量的值,需要用到get方法
示例代码:
class Person { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void getName() { return name; } public void getAge() { return age; } Person(String name, int age) { this.name = name; this.age = age; } } class Test { public static void main(String[] args) { Person p = new Person("Lucy", 20); p.setName("Linda"); } }
九、构造代码块
1.构造代码块的定义构造代码块是定义在类中的一个独立代码区间。构造代码块的作用是为对象进行初始化。对象一旦创建就立刻运行构造代码块,且运行优先级高于该类的构造方法。
2.构造代码和构造方法的区别
1)构造代码是给所有对象进行统一初始化;
2)构造方法是给对应的对象初始化
3.构造代码块的应用
将所有对象的共性属性或行为定义在构造代码块中,那么所有对象创建的时候同一执行构造代码块中的内容。
示例代码:
class Person { private String name; private int age; { this.name = "Travis"; this.age = 20; } Person(String name, int age) { this.name = name; this.age = age; } }
十、this关键字
1.this的概念this关键字代表调用
this所在方法的对象的引用,即哪个对象调用了
this所在的方法,
this就指向那个对象。
2.this关键字的应用
1)
this关键字用于区分局部变量和成员变量重名的情况;并且,定义类中方法时,如果需要在方法内部使用本类对象的时候,用
this指向这个对象
示例代码:
package test; public class Animal { private String type; private int leg; Animal(String type, int leg) { this.type = type; //this区分了成员变量和局部变量,并代表本类的对象 this.leg = leg; } }
2)this关键字可以用于构造方法间互相调用
示例代码:
package test; public class Animal { private String type; private int leg; Animal(String type) { this.type = type; //this区分了成员变量和局部变量,并代表本类的对象 } Animal(String type, int leg) { this(type); //this关键字以type为参数调用了第一个构造函数 this.leg = leg; } }
3)注意:
this关键字调用其他构造方法的语句只能写在构造方法的第一行,因为初始化动作要先执行
十一、static关键字
1.static关键字基本用法static关键字是一个修饰符,用于修饰成员变量和成员方法。被
static修饰的成员,称为静态成员,或类成员。当一个成员是所有对象所共享的时候,用
static关键字修饰,那么每次创建对象的时候,该成员就不会被初始化在堆内存中。
class Person { String name; static String country = "CN"; }
上述代码中,country被声明成静态变量,则该变量不再存在于堆内存中,而作为共享数据储存于方法区,如下图:
2.static关键字的特点
1)随着类的加载而加载
类一旦加载到内存,
static成员就已经在内存中被分配空间。同时,
static成员随着类的消失而消失,也就是说,
static成员的生命周期最长
2)优先于对象存在
静态随着类的加载而存在,对象创建后才存在
3)被所有对象共享
所有对象共享一份静态成员
4)可以直接被类名所调用
由于类刚加载的时候,还没有对象,而静态成员已经加载到内存,所以可以用类名直接调用
3.静态变量和成员变量的区别
1)存放位置不同
静态变量随着类的加载而存在与方法区中
成员变量随着对象的创建而存在于堆内存中
2)生命周期不同
静态变量生命周期等于类的生命周期,随着类存在消亡
成员变量生命周期随着对象存在消亡,生命周期较静态变量短
4.static关键字注意事项
不能把所有成员都定义成
static,因为:
1)不是所有成员都能被所有对象共享;
2)定义成
static的成员,生命周期随着类存在消亡,对象使用完毕,这些成员还存在于内存,浪费资源;
3)静态方法中不能引用非静态成员,即静态方法只能访问静态成员(非静态方法可以访问静态成员);
4)静态方法中不能出现
this,
super关键字
5.静态的利弊
利:
1)存储所有对象共享的成员于方法区,节省资源;
2)可以直接被类名调用,使用简单
弊:
1)生命周期过长,可能出现浪费资源的情况;
2)访问出现局限性(静态方法只能访问静态成员)
6.使用static关键字的时机
1)当对象中出现需要共享的数据时,使用
static关键字。这里的数据,指的是成员的值或功能,不是成员本身。成员本身称为共享的属性,而不是共享的数据,如
name成员变量,是
Person类的对象的共享属性,而非共享数据;
2)当成员方法没有对类中任何非静态成员变量进行操作的时候,该方法可以定义成静态成员方法
7.静态的应用
定义了
ArrayTools类,包含各种操作数组的方法。由于所有的方法都没有操作该类中的成员变量,根据
static关键字使用原则,声明该类中所有方法为静态成员方法。
示例代码:
package test; /** * 利用ArrayTools类实现冒泡排序,选择排序,普通查找和二分查找 * @author jeremy * */ public class TestArrayTools { public static void main(String[] args) { int[] arr = new int[]{3, 98, 56, 4, 10, 66, 27, 17}; //冒泡排序 System.out.println("Bubble Sort:"); ArrayTools.bubbleSort(arr); ArrayTools.printArray(arr); System.out.println("----------------------------------------------"); //选择排序 System.out.println("Select Sort:"); ArrayTools.selectSort(arr); ArrayTools.printArray(arr); System.out.println("----------------------------------------------"); //选择排序2 System.out.println("Select Sort Version 2:"); ArrayTools.selectSort_2(arr); ArrayTools.printArray(arr); System.out.println("----------------------------------------------"); //普通查找 System.out.println("Search array for 10:"); System.out.println(ArrayTools.search(arr, 10)); System.out.println("----------------------------------------------"); System.out.println("Search array for 11:"); System.out.println(ArrayTools.search(arr, 11)); System.out.println("----------------------------------------------"); //二分查找 System.out.println("Half Search array for 27:"); System.out.println(ArrayTools.halfSearch(arr, 27)); System.out.println("----------------------------------------------"); System.out.println("Half Search array for 99:"); System.out.println(ArrayTools.halfSearch(arr, 99)); System.out.println("----------------------------------------------"); //二分查找2 System.out.println("Half Search array Version 2 for 56:"); System.out.println(ArrayTools.halfSearch(arr, 56)); System.out.println("----------------------------------------------"); System.out.println("Half Search array Version 2 for -9:"); System.out.println(ArrayTools.halfSearch(arr, -9)); System.out.println("----------------------------------------------"); } } class ArrayTools { /** * 交换数组中两个值的位置 * @param arr 接受数组作为第一参数 * @param a 接受整型数据作为第二参数,用于标识数组元素 * @param b 接受整型数据作为第三参数,用于标识数组元素 */ private static void swap(int[] arr, int a, int b) { int tmp = arr[b]; arr[b] = arr[a]; arr[a] = tmp; } /** * 打印数组的方法 * @param arr 接受数组作为参数 */ 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] + "]"); } } } /** * 冒泡排序,相邻两书比较,小的数左移 * @param arr 接受数组作为参数 */ public static void bubbleSort(int[] arr) { for(int x = 0; x < arr.length; x ++) { for(int y = 0; y < arr.length - x - 1; y ++) { if(arr[y] > arr[y + 1]) { swap(arr, y, y + 1); } } } } /** * 选择排序一,前一个数和后一个做比较,若大于后一个数,则立刻交换位置 * @param arr 接受数组作为参数 */ 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); } } } } /** * 选择排序二,前一个数和后一个做比较,如果大于后一个,则交换下标值,让小的数继续比较 * 如果较小数的下标发生过变化,则和原数交换位置 * @param arr 接受数组作为参数 */ public static void selectSort_2(int[] arr) { int k; for(int x = 0; x < arr.length - 1; x ++) { k = x; for(int y = x + 1; y < arr.length; y ++) { if(arr[k] > arr[y]) { k = y; } } if(k != x) { int tmp = arr[k]; arr[k] = arr[x]; arr[x] = tmp; } } } /** * 普通查找,遍历数组,将每个元素和目标值作比较 * @param arr 接受数组作为第一参数 * @param key 接受整型目标值作为第二参数 * @return 匹配成功,返回下标;匹配失败,返回-1 */ public static int search(int[] arr, int key) { for(int x = 0; x < arr.length; x ++) { if(arr[x] == key) { return x; } } return -1; } /** * 二分法查找一 * @param arr 接受数组作为第一参数 * @param key 接受整型目标值作为第二参数 * @return 匹配成功,返回下标;匹配失败,返回-1 */ public static int halfSearch(int[] arr, int key) { int min = 0; int max = arr.length - 1; int mid = (min + max) / 2; while(arr[mid] != key) { if(arr[mid] < key) { min = mid + 1; } else { max = mid - 1; } if(min > max) { return -1; } mid = (min + max) / 2; } return mid; } /** * 二分法查找二 * @param arr 接受数组作为第一参数 * @param key 接受整型目标值作为第二参数 * @return 匹配成功,返回下标;匹配失败,返回-1 */ public static int halfSearch_2(int[] arr, int key) { int min = 0; int max = arr.length - 1; int mid = (min + max) / 2; while(min <= max) { if(arr[mid] < key) { min = mid + 1; } else if(arr[mid] > key) { max = mid - 1; } else { return mid; } } return -1; } }
8.静态代码块
1)格式
static { statement; }
2)特点
随着类的加载而执行,并且只执行一次。用于对类进行初始化。
示例代码:
class TestStatic { TestStatic() { System.out.print("b "); } static { System.out.print("a "); } { System.out.print("c "); } TestStatic(int x) { System.out.print("d "); } } class TestStaticMain { public static void main(String[] args) { new TestStatic(5); } }
上述代码的输出结果为:a c d
执行过程为:
1> 先执行
static代码块,由于其要初始化类,优先级最高,输出
a;
2> 后执行构造代码块,由于其要初始化对象,优先级介于构造方法和静态代码块间,输出
c;
3> 最后执行相应的构造方法,输出
d
注意:
静态代码块中不能访问非静态成员变量,构造代码块可以访问非静态变量。
示例代码:
class TestStatic { int num = 9; static { //错误,静态代码块先于非静态成员存在,无法访问非静态成员 System.out.print("a " + num); } { //正确,构造代码块初始化本类对象,可以访问该类的成员变量 System.out.print("c " + num); } } class TestStaticMain { public static void main(String[] args) { new TestStatic(); } }
输出:c9
9.主函数的属性
主函数的定义:
主函数是一个特殊函数,作为程序的入口,被jvm调用。主函数格式固定。
public:主函数无访问限制
static:主函数为静态,随着类的加载就存在于方法区
void:主函数没有返回值
mian:不是关键字,是能被jvm识别的特殊标识符
String[] args:函数的参数,参数类型为字符串数组
十二、对象的初始化过程
1.对象的初始化过程如下:1)通过虚拟机,加载类的
class文件到内存;
2)执行方法区静态代码块(如有),对类进行初始化;
3)在堆内存中开辟对象
new Person(),及其类成员变量的储存空间,并对成员变量进行初始化;在栈内存中开辟
main方法和该对象引用的储存空间;
4)对类成员变量进行显式初始化(如有);
5)执行构造代码块(如有),对对象进行初始化;
6)执行构造方法,调用相应的构造方法对成员变量进行初始化;
7)将内存地址赋给栈内存中该对象的引用
2.对象调用非静态成员方法过程
1)从方法区将要调用的非静态方法加载到栈内存;
2)将该对象的引用的内存地址,赋给要调用的方法中自带的this关键字,此时,this指代的就是该对象的引用;
3)内存地址赋值完毕,this指向该对象,将栈内存中变量的值,赋给堆内存中对象的成员变量,完成赋值,结束对非静态方法的调用
十三、设计模式之单例设计模式
设计模式是解决某一类问题最行之有效的方法。作为Java23种设计模式中的一种,单例设计模式解决了一个类在内存中只能存在一个对象的问题,即保证一个类,在内存中只有一个对象。想要保证对象唯一性:
1.禁止其他程序建立该类的对象;
2.在该类中自定义一个对象;
3.开放端口,让其他程序访问该对象
实现:
1.私有化构造方法;
2.在该类中创建一个本来对象;
3.提供方法获取该对象
饿汉式:
class Single { //私有化构造方法,其他程序不能创建该类对象 private Single() {} //在本类中,创建静态的本类对象 private static Single s = new Single(); //对其他程序提供静态方法,获取该类对象 public static Single getInstance() { return s; } } class TestSingle { public static void main(String[] args) { //调用Single类的静态方法,获取Single对象 Single s = Single.getInstance(); } }
单例模式内存图:
图示说明:
1.
Single类在加载的时候,其静态成员变量
s,静态成员函数
getInstance()以及构造函数都已加载到方法区;在
Single类中创建
Single对象的时候,已经将
Single对象的内存地址赋给方法区中的静态变量
s;
2.
mian()方法中调用了
getInstance()方法后,返回的
Single对象
s将
Single对象的内存地址赋给栈内存中的变量
s,即栈内存中的变量
s现在指向堆内存中的
Single对象,是
Single对象的引用;
3.由于
Single类的构造方法被声明为私有,则外部程序无法创建该类的对象;若有代码
Single s1 = Single.getInstance();则继续执行上述两个步骤,结果是
s1仍然指向堆内存中的同一
Single对象,这保证了
Single对象的唯一性
懒汉式:
class Single { //私有化构造方法,其他程序不能创建该类对象 private Single() {} //延迟创建本类对象 private static Single s = null; //对其他程序提供静态方法,获取该类对象 public static Single getInstance() { //判断,如果s为空,则创建本类对象 if(s == null) { s = new Single(); } //返回该对象 return s; } }
饿汉式和懒汉式的不同:
饿汉式:
Single类一旦加载到内存,就马上创建对象
懒汉式:
Single类加载到内存时,对象没有被创建。只有调用了
getInstance()方法时,才创建对象
开发时,用饿汉式
———Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ———
相关文章推荐
- 黑马程序员——Java基础之面向对象(3)——第九篇
- 黑马程序员---Java基础--08天(面向对象之三多态)
- 黑马程序员_Java基础_面向对象(概述、类与对象关系、成员变量、封装private、构造函数和构造代码块、this关键字)
- 黑马程序员:java基础学习——面向对象
- 黑马程序员_Java基础_面向对象(内部类、异常1)
- 黑马程序员——Java基础之面向对象(4)——第十篇
- 黑马程序员_Java基础_面向对象(异常2、练习题、导包)
- 黑马程序员____基础____java的面向对象
- 黑马程序员_Java基础_面向对象(Static的使用、对象初始化和调用成员过程、单例设计模式)
- 黑马程序员-----笔记整理(java基础五-------面向对象--多态)
- 黑马程序员-Java语言基础–面向对象 第9天
- 黑马程序员-Java语言基础–面向对象 第5天
- 黑马程序员_Java基础_面向对象(继承、子父类变量和函数以及构造函数特点、final关键字、抽象类、模版方法模式、接口)
- 黑马程序员——Java基础之面向对象(1)——第七篇
- 黑马程序员---Java基础--07天(面向对象之三)
- 黑马程序员-Java语言基础 –面向对象 第7天
- 黑马程序员-Java语言基础–面向对象 第8天
- 黑马程序员-----java基础三(之面向对象)
- 黑马程序员_Java基础_面向对象(多态、Object类相关方法)
- 黑马程序员_java编程基础10面向对象