Java深入(高新技术)(二):开发环境、静态导入、可变参数、增强for循环、基本数据类型的自动拆箱与装箱、享元模式

时间:2023-02-18 11:16:42

深切怀念传智播客张孝祥老师,特将其代表作——Java基础加强视频研读两遍,受益颇丰,记以后阅

基础最重要,但是高级技术又能从反面强化基础。

IDE开发工具都支持使用工程化方式管理一个项目的程序开发过程,一般来说一个相对独立的项目就是一个工程,一个项目中涉及的多个java文件,资源文件等用一个工程进行管理。(在这里可以看看以前工作间中的某个工程的结构),在不使用工程管理的情况下,如果一个项目中包括多个Java源文件,编程人员需要精心维护这些源文件之间、以及源文件与其它文件的目录关系,需要逐一编译这些源文件,需要手工启动运行编译后的结果。如果将一个程序的所有源文件用一个工程来组织,开发工具能对所有源文件集中管理,记住每个源文件的位置和相互关系。工程中有哪几个源文件、启动类是哪个、启动参数设置等配置信息在工程中都记录。

一个workspace可以包含多个project,一个workspace保留了eclipse的一套环境选项的配置,例如,所使用的javac和java命令,等等,细节请查看window->preferences。如果要为eclispe再配置一套环境选项,可以再创建一个workspace。Packageexplorer视图窗口中的filters菜单项,可以显示空的父包(此功能默认是关闭的)。

高版本的java能否运行低版本的javac编译的程序?能

低版本的java能否运行高版本的javac编译的程序?不能

 

 

1.5新特性之静态导入

import语句可以导入一个类或某个包中的所有类

import static语句导入一个类中的某个静态方法或所有静态方法

1.5新特性之可变参数

问题:一个方法接受的参数个数不固定,例如:

       System.out.println(countScore(2,3,5));

       System.out.println(countScore(1,2,3,5));

可变参数的特点:

       只能出现在参数列表的最后;这个要记住

       ...位于变量类型和变量名之间,前后有无空格都可以;

       调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。

1.5新特性之增强for循环

语法:

       for ( type 变量名:集合变量名)  { … }

注意事项:

       迭代变量必须在( )中定义!

       集合变量可以是数组或实现了Iterable接口的集合类

举例:

       public static intadd(int x,int ...args) {

         int sum = x;

         for(int arg:args) {

                   sum += arg;

         }

         return sum;

       }

1.5新特性之基本数据类型的自动拆箱与装箱

       自动装箱:

                       Integernum1 = 12;

       自动拆箱:

                       System.out.println(num1+ 12);

       基本数据类型的对象缓存:

                   Integer num1= 12;

                   Integer num2= 12;           //这块相等,<=127都是真的,放在内存中

                   System.out.println(num1== num2);

                   Integer num3= 129;    //这块不相等,因为是对象

                   Integer num4= 129;

                   System.out.println(num3== num4);

 

       Integer num5 =Integer.valueOf(12);

       Integer num6 =Integer.valueOf(12)  ;   这块的道理同上

       System.out.println(num5== num6);   //相等

享元模式【Flyweight

当一个应用中使用了大量的对象,这些对象造成了很大的存储开销,而对象的大部分状态或参数都是相同(内部状态)的时候,可以考虑使用享元模式,使用享元模式可以是这些对象引用都共享相同的实例,降低存储开销,而对象之间的不同的状态参数(外部状态)则使用外部参数传入来实现。

享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的损耗。享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)

  一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。

  一个外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。

  享元模式可以分成单纯享元模式复合享元模式两种形式。

 

也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。比如说一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象。如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了。那么如果要是每个字母都共享一个对象,那么就大大节约了资源。
  在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweight(享元)模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个对象存储池(FlyweightPool)来存放内部状态的对象。Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合很多,下面举个例子:

先定义一个抽象的Flyweight类:

packageFlyweight;

publicabstract class Flyweight{

publicabstract void operation();

}

实现一个具体类:

package Flyweight;  

public class ConcreteFlyweight extends Flyweight{  

private String string;  

public ConcreteFlyweight(String str){  

string = str;  

}  

public void operation()  

{  

System.out.println("Concrete---Flyweight : " + string);  

}  

}  

实现一个工厂方法类:

package Flyweight;  

import java.util.Hashtable;  

public class FlyweightFactory{  

private Hashtable flyweights = new Hashtable();//----------------------------1  

public FlyweightFactory(){}  

public Flyweight getFlyWeight(Object obj){  

Flyweight flyweight = (Flyweight) flyweights.get(obj);//----------------2  

if(flyweight == null){//---------------------------------------------------3  

//产生新的ConcreteFlyweight   

flyweight = new ConcreteFlyweight((String)obj);  

flyweights.put(obj, flyweight);//--------------------------------------5  

}  //有了就直接拿来用,没有的话就新创建

return flyweight;//---------------------------------------------------------6  

}  

public int getFlyweightSize(){  

return flyweights.size();  

}  

}  

这个工厂方法类非常关键,这里详细解释一下:
  在1处定义了一个Hashtable用来存储各个对象;在2处选出要实例化的对象,在6处将该对象返回,如果在Hashtable中没有要选择的对象,此时变量flyweightnull,产生一个新的flyweight存储在Hashtable中,并将该对象返回。
最后看看Flyweight的调用:

package Flyweight;  

import java.util.Hashtable;  

public class FlyweightPattern{  

FlyweightFactory factory = new FlyweightFactory();   

Flyweight fly1;  

Flyweight fly2;  

Flyweight fly3;  

Flyweight fly4;  

Flyweight fly5;  

Flyweight fly6;  

/** *//** Creates a new instance of FlyweightPattern */  

public FlyweightPattern(){  

fly1 = factory.getFlyWeight("Google");  

fly2 = factory.getFlyWeight("Qutr");  

fly3 = factory.getFlyWeight("Google");  

fly4 = factory.getFlyWeight("Google");  

fly5 = factory.getFlyWeight("Google");  

fly6 = factory.getFlyWeight("Google");  

}  

public void showFlyweight(){  

fly1.operation();  

fly2.operation();  

fly3.operation();  

fly4.operation();  

fly5.operation();  

fly6.operation();  

int objSize = factory.getFlyweightSize();  

System.out.println("objSize = " + objSize);  

}  

public static void main(String[] args){  

System.out.println("The FlyWeight Pattern!");  

FlyweightPattern fp = new FlyweightPattern();  

fp.showFlyweight();  

}  

}  

下面是运行结果:

Concrete---Flyweight : Google  

Concrete---Flyweight : Qutr  

Concrete---Flyweight : Google  

Concrete---Flyweight : Google  

Concrete---Flyweight : Google  

Concrete---Flyweight : Google  

objSize = 2  
 我们定义了6个对象,其中有5个是相同的,按照Flyweight模式的定义“Google”应该共享一个对象,在实际的对象数中我们可以看出实际的对象是只有2个。

总结:
Flyweight(享元)模式是如此的重要,因为它能帮你在一个复杂的系统中大量的节省内存空间。JAVA语言中,String类型就是使用了享元模式。String对象是final类型,对象一旦创建就不可改变。在JAVA中字符串常量都是存在常量池中的,JAVA会确保一个字符串常量在常量池中只有一个拷贝。Stringa="abc",其中"abc"就是一个字符串常量。

熟悉java的应该知道下面这个例子:

[java]view plaincopyprint?

String a = "hello";  

String b = "hello";  

if(a == b)  

System.out.println("OK");  

else  

System.out.println("Error");  

Stringa = "hello";

Stringb = "hello";

if(a== b)

System.out.println("OK");

else

System.out.println("Error");

输出结果是:OK。可以看出if条件比较的是两ab的地址,也可以说是内存空间
核心总结,可以共享的对象,也就是说返回的同一类型的对象其实是同一实例,当客户端要求生成一个对象时,工厂会检测是否存在此对象的实例,如果存在那么直接返回此对象实例,如果不存在就创建一个并保存起来,这点有些单例模式的意思。通常工厂类会有一个集合类型的成员变量来用以保存对象,如hashtable,vector等。在java中,数据库连接池,线程池等即是用享元模式的应用。