因为上上次举了个例子,昨天和女朋友道了一天的歉,所以昨天没有更博,哎,女朋友就是麻烦!不过我也很无奈啊,毕竟我还不想恢复我单身狗的身份!好了,接着上次的话题,这次给大家介绍内存优化。
上次给大家介绍了OOP的三大特点之一的封装,将数据和对数据的操作放在一起,从而保证了数据的安全。那么问题来了!!!!
如果当我们需要很多功能类的时候,如果对每个类都去创建该类的对象的话是非常消耗内存的,要知道在Java中,每使用一次new关键字就会在堆内存中开辟空间。(关于内存结构后续的文章中会为大家提到)
回顾一下我们猜单词小程序中的Start这个类
public class Start {
public void init() {
//创建sq对象
SqlDemo sq = new SqlDemo();
//调用该对象的getArr1()方法获取正确的中文意思
String str1 = sq.getArr1();
//创建in对象
Input in = new Input();
//调用该对象的getAns()方法获取用户输入的值
String str2=in.getAns();
//创建ju对象
Judge ju = new Judge();
//调用该对象的contrast方法来判断用户的答案是否正确
boolean flag = ju.contrast(str1, str2);
//创建show对象
Show show = new Show();
//调用该对象的showMessage方法来显示用户的反馈信息
show.showMessage(flag);
}
}
这个类中创建了好几个对象,这还是在一个小程序中,咱们想想,如果是在大型的项目中,难道就这么不停的创建对象吗?(当然OOP的思想就是创建对象,再去通过对象调用方法)但是如果有100个类难道就去创建100个对象吗?如果是1000个呢??毫无疑问,这样是不明智的。对于这种情况就需要对内存进行优化了。
在Java中提供了一个关键字static,表示静态的意思。
看一下官方的解释:
static:静态成员修饰符,被static修饰后的成员,在编译时由内存分配一块内存空间,直到程序停止运行才会释放!
肯定不好理解对吧,没关系,我们只需要从上面的官方解释里知道:当一个类在编译时期,系统就会给static分配一块内存空间,而这个时候内存里还没有任何对象!(关于这个很好理解,大家只需要记住,只有new出现的时候才会有对象的存在)。也就是说static成员对该类的所有对象都是可见的!!!对不对!
因为static成员早先一步进入内存嘛!这一点大家一定要明白!
所以,在一个类中,被static修饰的成员对于该类所有的对象都是可见的,也就是说该成员可以被该类的所有对象访问,对不对!!!
好了,关于概念就给大家介绍到这里了!下面来说说static成员怎么访问呢?
首先,毫无疑问肯定是能够通过对象去访问的,但是上面就说了,static成员在对象还不存在的时候就已经在内存中分配空间了,那么在对象还没有被创建的时候怎么去访问呢??
在Java中,提供了一种专门的方式去访问static成员,就是通过类名直接去访问!!!
那么问题来了,这样做的好处是什么呢?
好处肯定就是你不用创建对象了嘛,直接用类名去调用。所以static成员也被叫做类成员。来体会一下下面的这段代码:
public class SqlDemo {
//私有化构造方法,防止外部创建本类对象
private SqlDemo() {
}
//私有化共享数据,防止外界对数据的篡改,保证数据的安全性
private static String[] arr1= {"deprecated","category","figure","confirm","profile","argument"};
private static String[] arr2= {"不赞成","类型","数字","确认","侧面","争论"};
//对外提供公有的访问方法
public static String getArr1() {
int i= (int)(Math.random()*arr1.length);
System.out.println(arr1[i]);
return arr2[i];
}
}
这是把前面的猜单词小程序中的SqlDemo类进行了改进,
大家以看到,两个字符串数组都被static修饰了。同样的geArr1方法也被静态修饰了。(构造方法下文中会解释!)
这样做的好处就是可以通过类名去调用getArr1方法获取数组中的元素,而不用去创建SqlDemo类的对象。
同样的,来看下面的这一段代码:
public class Input {
//私有化构造方法,防止外部创建本来对象
private Input(){
}
// 创建键盘录入对象
Scanner in = new Scanner(System.in);
public String getAns() {
// 接受用户的输入值
String sum = in.nextLine();
// 返回用户输入的值
return sum;
}
//对外提供共有方法,返回一个本类对象
public static Input getInput() {
return new Input();
}
}
同样的,该类中提供了一个static方法getInput,(其实可以直接将getAns方法用static修饰即可,不过这里小风主要是想给大家介绍一种设计模式–单例模式,所以才多定义了一个方法)
好了,来解释一下这段代码。emmmm 想了想,要解释这段代码的话还要给大家提一个概念,就是new关键字,现在就来解释一下new关键字把,
来看看官方的解释:new关键字的作用就是在你声明了一个对象后,给对象分配相应内存
当然大家肯定理解不了,没关系。来回顾一下之前的代码。
SqlDemo sq = new SqlDemo();
Input in = new Input();
看这两行代码,new关键字后的内容都是一个和类名相同的一个方法,对不对!好了,先给大家说,这个方法叫做构造方法,大家先不要慌,对于构造方法官方的解释是用于初始化对象,没错!
你想想,当new关键字执行之后,系统就会在内存中分配一块内存空间来存放该对象,这个时候就需要这个方法来对该对象进行初始化。
好了,关于构造方法会在下一回给大家详细的介绍。
回到这次的话题中,上述的两段代码中不难发现,开头都有一段代码,相信大家都已经能够知道是什么吧,
没错,就是构造方法!但是再仔细一看,构造方法被private修饰了!!这是为什么呢???
相信大家从注释中已经看到了这样的目的吧,没错,就是构造方法私有化,返防止外界创建本类的对象!
那么问题来了!为什么要防止外部创建本类的对象呢??
好了,第一点肯定是安全嘛,也就是保证了对象的唯一性。另外一点就是优化内存!
你想想:当系统中只存在一个对象的时候,对于一些需要频繁创建和销毁的对象来说,采用单例模式无疑可以提高系统的性能。因此这种方式可以节约系统资源,
好了,在Java开发中经常会遇到共享数据的问题,对于这种问题,一般多采用单例来解决。额 ,说的有点操之过急哈!
单例模式就是将一个类中的构造方法私有化,通过本类中的公有方法对外部返回一个本类的对象。Input类就是一个典型的单例模式。
好了,关于单例模式就先给大家介绍到这里,大家只需要知道,单例模式的核心思想就是将构造方法私有化,防止外部创建本类对象。
好了,回到我们的猜单词的小程序中,既然改变了SqlDemo和Input类,那么我们对其他类也做一下优化,先来看看Show类
public class Show {
public static void showMessage(boolean flag) {
if (flag) {
System.out.println("恭喜你答对了!");
}
else {
System.out.println("不好意思,你答错了");
}
return;
}
}
看,showMessage方法被修饰成了静态成员,于是在Start类中就不用去创建该类的对象了,因此,直接同通过类名去调用就可以了。
再看Start类:
public class Start {
//不需要每次显示结果是否正确
public static boolean init() {
String str1 = SqlDemo.getArr1();
String str2=Input.getInput().getAns();
boolean flag = Judge.contrast(str1, str2);
return flag;
}
//需要每次显示结果是否正确
public void show() {
String str1 = SqlDemo.getArr1();
String str2=Input.getInput().getAns();
Judge ju = new Judge();
boolean flag = ju.contrast(str1, str2);
Show.showMessage(flag);
}
}
看第一个init()方法中,不用创建他们的对象就能够获取到他们的方法,
同时,静态依然保留了通过对象去访问的访问规则,比如show()方法里还是可以去创建Judge的对象ju,然后通过ju去访问方法。
好了,到这里就已经差不多结束了。
来看一下咱们的程序的入口:
public class Test {
public static void main(String[] args) {
new Start().show();
}
}
简单吗?大家可能有点好奇,new Start().show();
是啥意思。不要慌,下一篇文章中将会给大家介绍!
额 ,对了,别忘了把Judge类中的方法也用static修饰哈!
哎,算了,还是给出程序的完整到代码把:
package oopDemo3;
/**
*
* */
public class SqlDemo {
//私有化构造方法,防止外部创建本类对象
private SqlDemo() {
}
//私有化共享数据,防止外界对数据的篡改,保证数据的安全性
private static String[] arr1= {"deprecated","category","figure","confirm","profile","argument"};
private static String[] arr2= {"不赞成","类型","数字","确认","侧面","争论"};
//对外提供公有的访问方法
public static String getArr1() {
int i= (int)(Math.random()*arr1.length);
System.out.println(arr1[i]);
return arr2[i];
}
}
package oopDemo3;
import java.util.Scanner;
/**
* 用来实现用户从键盘输入一个字符串的功能
*
*/
public class Input {
//私有化构造方法,防止外部创建本来对象
private Input(){
}
// 创建键盘录入对象
Scanner in = new Scanner(System.in);
public String getAns() {
// 接受用户的输入值
String sum = in.nextLine();
// 返回用户输入的值
return sum;
}
//对外提供共有方法,返回一个本类对象
public static Input getInput() {
return new Input();
}
}
package oopDemo3;
/**
* 判断用户的输入是否正确
*
* */
public class Judge {
public static boolean contrast(String arr1,String arr2) {
return arr1.equals(arr2);
}
}
package oopDemo3;
/**
* 给用户反馈信息
*
* */
public class Show {
public static void showMessage(boolean flag) {
if (flag) {
System.out.println("恭喜你答对了!");
}
else {
System.out.println("不好意思,你答错了");
}
return;
}
}
package oopDemo3;
/**
* 实现代码的逻辑功能
*
* */
public class Start {
//不需要每次显示结果是否正确
public static boolean init() {
String str1 = SqlDemo.getArr1();
String str2=Input.getInput().getAns();
boolean flag = Judge.contrast(str1, str2);
return flag;
}
//需要每次显示结果是否正确
public void show() {
String str1 = SqlDemo.getArr1();
String str2=Input.getInput().getAns();
Judge ju = new Judge();
boolean flag = ju.contrast(str1, str2);
Show.showMessage(flag);
}
}
package oopDemo3;
public class Test {
public static void main(String[] args) {
new Start().show();
}
}
好了,这才是一个完整的Java小程序。
大家快去试试吧!
下一篇我们就进入到了Java中的OOP思想的核心部分了!期待不