“Java”的版本间的差异

来自tomtalk
跳转至: 导航搜索
Java数字格式化
Tom讨论 | 贡献
guid()
第476行: 第476行:
 
     return temp;
 
     return temp;
 
}
 
}
 +
</source>
 +
 +
===Java数字格式化===
 +
 +
<source lang="java">
 +
double pi = 3.1415927;//pi 
 +
 +
// 取一位整数 
 +
System.out.println(new DecimalFormat("0").format(pi));// 3 
 +
 +
// 取一位整数和两位小数 
 +
System.out.println(new DecimalFormat("0.00").format(pi));// 3.14 
 +
 +
// 取两位整数和三位小数,整数不足部分以0填补。 
 +
System.out.println(new DecimalFormat("00.000").format(pi));// 03.142 
 +
 +
// 取所有整数部分 
 +
System.out.println(new DecimalFormat("#").format(pi));// 3 
 +
 +
// 以百分比方式计数,并取两位小数 
 +
System.out.println(new DecimalFormat("#.##%").format(pi));// 314.16% 
 +
 +
long c = 299792458;
 +
 +
// 显示为科学计数法,并取五位小数 
 +
System.out.println(new DecimalFormat("#.#####E0").format(c));// 2.99792E8 
 +
 +
// 显示为两位整数的科学计数法,并取四位小数 
 +
System.out.println(new DecimalFormat("00.####E0").format(c));// 29.9792E7 
 +
 +
// 每三位以逗号进行分隔。 
 +
System.out.println(new DecimalFormat(",###").format(c));// 299,792,458 
 +
 +
// 将格式嵌入文本 
 +
System.out.println(new DecimalFormat("光速大小为每秒,###米。").format(c));
 
</source>
 
</source>
  

2019年12月17日 (二) 03:43的版本



AES加密

java代码

    // 密钥
    private final static String secretKey = "key123";
    private final static String salt = "0123456789abcdef" ;//KeyGenerators.string().generateKey();
 
    /**
     * 加密
     *
     * @param plainString 明文
     * @return
     */
    private static String encrypt(String plainString) {
        // 明文
        byte[] byteArray = plainString.getBytes();
 
        // 加密,设置密钥和随机数
        byte[] cipherArrayTemp = Encryptors.standard(secretKey, salt).encrypt(byteArray);
        byte[] cipherArray = Base64.encode(cipherArrayTemp);
        return new String(cipherArray);
    }
 
    /**
     * 解密
     *
     * @param cipherString 密文
     * @return
     */
    private static String decrypt(String cipherString) {
        // 密文
        byte[] byteArray = cipherString.getBytes();
        byte[] plainArrayTemp = Base64.decode(byteArray);
 
        // 解密
        byte[] plainArray = Encryptors.standard(secretKey, salt).decrypt(plainArrayTemp);
        return new String(plainArray);
    }

javascript代码

https://cdn.bootcss.com/crypto-js/3.1.9-1/crypto-js.js

  // 可在第三方网站解密
  let word = 'hello world!';
  let key = 'key123';
  var iv = '0123456789abcdef';
  var attr = {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  };
  console.log(CryptoJS.AES.encrypt(word, key, attr).toString());
  console.log(CryptoJS.AES.decrypt(CryptoJS.AES.encrypt(word, key), key).toString(CryptoJS.enc.Utf8));

Base64,Base32,Base16进制的区别

刚刚接触Base时,没有太注重区分Base64,Base32,Base16的区别,后面每一次遇到就要去一个一个试,这次花了点时间记下了一下Base的区别,顺便写一下。

在看了大佬们的分析后http://blog.51cto.com/xiaoqin00/1718416,我截取了几个关键的记住这些就能区分Base之间的区别了:

Base64:

包含大写字母(A-Z),小写字母(a-z),数字(0-9)以及+/;

Base32:

而Base32中只有大写字母(A-Z)和数字234567;

Base16:

而Base16就是16进制,他的范围是数字(0-9),字母(ABCDEF);

顺便说一句,当ASCll用Base加密达不到所对应的位数的时候用=号补齐;

在这里附带由三种Base加密的:I love you!

Base64:SSBsb3ZlIHlvde+8gQ==

Base32:JEQGY33WMUQHS33V566IC===

Base16:49206c6f766520796f75efbc81

Spring Security取username

前台

<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %>
<security:authentication property="principal.username"></security:authentication>

后台

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = "";
 
if (principal instanceof UserDetails) {
    username = ((UserDetails) principal).getUsername();
} else {
    username = principal.toString();
}
 
System.out.println(username);

favicon.ico引起的spring security登录后跳转错误

在使用spring security登录的时候,用户在某些情况下登录成功的时候莫名被重定向到favicon.ico。

之前一直没发现这个问题是因为在项目中存在favicon.ico文件,这个请求被nginx处理了而未转发给tomcat。

这次因为偷懒还没来得及配置nginx,结果就出现了上面的问题。

出现上述问题的原因是:基本大多数浏览器都会请求favicon.ico这个图标文件用来展示在浏览器的URL地址前面,而这个文件被spring security保护了,所以…有下面的流程:

the user requests URL "/". This URL is cached.

the browser makes a requests to "/favicon.ico". This URL becomes the new URL where to redirect to upon authentication.

the user posts the login form and is redirected to "/favicon.ico"

而解决办法是将favicon.ico加入允许匿名访问.

<http pattern="/favicon.ico" security="none"/>

如何在mac上安装gradle

首先,先download最新版本的gradle,网址如下:

http://www.gradle.org/get-started

然后将下载下来的zip包放在你要安装的路径上,我安装在

/usr/local/bin;

然后打开电脑上的.bash_profile文件,输入以下命令:

GRADLE_HOME=/usr/local/bin/gradle-1.8;
export GRADLE_HOME
export PATH=$PATH:$GRADLE_HOME/bin

然后再在console上输入以下命令:

source ~/.bash_profile

这样就安装成功啦,可以通过以下命令来查看是否安装成功。

gradle -version

SPRING MVC 的请求参数获取的几种方法

<form method="post" action="hao.do">
    a: <input id="a" type="text" name="a"/>
    b: <input id="b" type="text" name="b"/>
    <input type="submit" value="Submit" />
</form>

方法1:

public class Pojo{
    private String a;
    private int b;
}
 
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pojo") Pojo pojo) {
    return "helloWorld";
}

方法2:

@RequestMapping(method = RequestMethod.GET)
public String get(HttpServletRequest request, HttpServletResponse response) {
    System.out.println(request.getParameter("a"));
    return "helloWorld";
}

spring mvc 静态资源 404问题

修改web.xml文件,增加对静态资源的url映射。

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
 
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>

在web.xml中添加好配置后,在jsp页面就可以引用这些静态资源了。

这里还需要说明的是:这种方法不能访问WEB-INF目录下的静态资源,也就是js目录必须是web根(可能是webapp,webContent等)目录下,否则是不能引用的。

java中List的初始化问题

我声明了一个

List<String[]> users = null;

然后 使用 add()方法想这个List中加入元素的时候为啥会出现空指针啊。

List当然不能初始化为null,

List<String[]> users = new LinkedList<String[]>();

就可以了,然后添加元素就不会出现空指针了。

Spring学习

http://www.tutorialspoint.com/spring/spring_mvc_hello_world_example.htm

Spring Security Tutorial

如何在两到三个月之内熟悉 数据库,JavaWeb、框架,达到能写项目的水平?

谈谈对ssh三大框架的理解?

SSH框架一般指的是Struts、Spring、Hibernate,后来Struts2代替了Struts。最近5年,Struts2已经被Spring MVC代替,而Hibernate基本也被iBatis/MyBatis代替。

所以你真正需要了解的是Spring,Spring你需要了解两个概念AOP和IOC,更进一步就是Spring的核心技术“动态代理”。

持久层框架看看Hibernate/iBatis/MyBatis,研究一下Spring的数据库事务管理,各个持久层框架式如何实现ORM的,了解至少一种缓存框架,知道什么是数据库连接池。和数据库的交互最核心的不是ORM,而是掌握和数据库相关的能力,比如数据库编程、SQL优化、对范式的理解。

MVC框架Struts2和Spring MVC,你需要知道他们在web.xml文件里配置了一些什么,Struts2/Spring MVC接到前台请求之后经过哪些步骤之后转到Action/Controller,return之后Struts2/Spring MVC又作了些什么。还有就是Filter、Listener和Struts2/Spring MVC的拦截器各有什么特点,适合处理什么样的问题。

java开发环境

  • 安装JDK
  • 设置环境变量
   JAVA_HOME = C:\Program Files\Java\jdk1.8.0_66
   PATH = C:\ProgramData\Oracle\Java\javapath;%JAVA_HOME%\bin;
   CLASSPATH = %JAVA_HOME%\lib; %JAVA_HOME%\lib\dt.jar; %JAVA_HOME%\lib\tools.jar;
  • 安装tomcat
  • 安装IntellJ idea
  • 新建项目,关联tomcat
  • 部署项目:把IntelliJ项目的web目录上传到外网虚拟站点根目录就可以了。
jar xf tomcat.war
chown -R www.www ./*
service tomcat restart

数据库连接不上,把mysql-connector-java-5.1.18-bin.jar放到tomcat/lib目录下,重启。

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

Add mysql.connector-java-x.x.x-bin.jar to your libraries folder. No need to import anything. Have a good one.

别忘了重户tomcat

在IntellIj IDEA中JSP页面 cannot resolve method getParameter("")的解决方案

原来,是我在导入jar包的时候应该选择Platform setting下的global libraries,然后只要导入servlet.jar即可!

compareto, equals, == 在java中相对于值和引用

1.compareto 是判断一个对象的值是否包含包含另一个对象的值; compareto 是比较,比如比较数字大小

例如"abcds".compareto("ab")就是判断abcds中是否含有ab

2.equals 是比较两个对象的值

3.==是比较两个对象内存地址

String A = "abcd";
String B = "abcd"; 
 
A == B;       //ture   
A.equals(B);  //true
 
String A = new String("abcd");
String B = new String("abcd");
A == B;        //false  
A.equals(B);   //true

一个很诡异的bug,原来是由int精度引起的

import java.util.*; 
import java.text.SimpleDateFormat;
 
public class hello { 
 
 
    public static void main(String[] args) {  
 
        int[] ebbing = {1, 2, 4, 7, 15, 30, 50, 70, 100, 150, 200, 150, 200, 300, 400};
 
        getToday((long)ebbing[0] * 3600 * 24 * 1000); 
        getToday((long)ebbing[1] * 3600 * 24 * 1000); 
        getToday((long)ebbing[2] * 3600 * 24 * 1000); 
        getToday((long)ebbing[3] * 3600 * 24 * 1000); 
        getToday((long)ebbing[4] * 3600 * 24 * 1000); 
        getToday((long)ebbing[5] * 3600 * 24 * 1000); 
        getToday((long)ebbing[6] * 3600 * 24 * 1000); 
        getToday((long)ebbing[7] * 3600 * 24 * 1000); 
        getToday((long)ebbing[8] * 3600 * 24 * 1000); 
    } 
 
    // int为整数类型,在存储的时候,用4个字节存储,范围为-2,147,483,648到2,147,483,647。
    // 原用的是getToday(int offset_ms),这样在第6个日期,就超出范围了。
    public static String getToday(long offset_ms) {
 
    	SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 
		Date date = new Date(System.currentTimeMillis() + offset_ms);
		String today = dateFormat.format(date);
 
        System.out.println(offset_ms + " " + today); 
 
		return today;
    } 
}
# java hello
86400000 2014-05-14
172800000 2014-05-15
345600000 2014-05-17
604800000 2014-05-20
1296000000 2014-05-28
2592000000 2014-06-12
4320000000 2014-07-02
6048000000 2014-07-22
8640000000 2014-08-21

poi导出excel文件、下载

@RequestMapping(value = "batchCardNoExport", method = RequestMethod.GET)
public void batchCardNoExport(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 创建Excel的工作书册 Workbook,对应到一个excel文档
    HSSFWorkbook wb = new HSSFWorkbook();
 
    // 创建Excel的工作sheet,对应到一个excel文档的tab
    HSSFSheet sheet = wb.createSheet("sheet1");
 
    HSSFRow row;
    HSSFCell cell;
 
    for (int i = 0; i < 60; i++) {
        row = sheet.createRow(i); // 创建Excel的sheet的一行
        for (int j = 0; j < 30; j++) {
            cell = row.createCell(j); // 创建一个Excel的单元格
            cell.setCellValue("hello world " + i + " " + j);
        }
    }
 
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", "attachment; filename=filename.xls");
    wb.write(response.getOutputStream()); // Write workbook to response.
    wb.close();
}

java打印数组

将数组转化为有序的List打印出来

import java.util.Arrays; 
 
public class Hello { 
    public static void main(String[] args) {  
        String pool[] = {"dog", "cat", "pig", "main", "fish"};
        System.out.println(Arrays.asList(pool));
    }
}

hello world

public class HelloWorld{ 
    public static void main(String[] args) {  
        System.out.println("Hello World!"); 
    }
}

JAVA中int转String类型有三种方法

int i = 123;
 
String s = String.valueOf(i);
 
String s = Integer.toString(i);
 
String s = i + "";
 
//字符转数字
String str = "123456";
 
i = Integer.parseInt(str);

生成随机字符

private String RandomString(int length, String type) {
    String number = "0123456789";
    String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    Random random = new Random();
    StringBuffer sb = new StringBuffer();
 
    for (int i = 0; i < length; i++) {
        if (type.equals("number")) {
            int num = random.nextInt(number.length());
            sb.append(number.charAt(num));
        } else {
            int num = random.nextInt(str.length());
            sb.append(str.charAt(num));
        }
    }
 
    return sb.toString();
}

jdk Path设置

只要在Path变量的头部添加如下路径:

C:\Program Files\Java\jdk1.5.0\bin;

就可以了。

常用代码

随机取读取数据库的一道题

Random random    = new Random(System.currentTimeMillis());
int index_random = random.nextInt(listItem.size());

guid()

private String guid() {
    UUID uuid = UUID.randomUUID();
    String str = uuid.toString();
 
    // 去掉"-"符号
    String temp = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
    return temp;
}

Java数字格式化

double pi = 3.1415927;//pi   
 
// 取一位整数   
System.out.println(new DecimalFormat("0").format(pi));// 3   
 
// 取一位整数和两位小数   
System.out.println(new DecimalFormat("0.00").format(pi));// 3.14   
 
// 取两位整数和三位小数,整数不足部分以0填补。   
System.out.println(new DecimalFormat("00.000").format(pi));// 03.142   
 
// 取所有整数部分   
System.out.println(new DecimalFormat("#").format(pi));// 3   
 
// 以百分比方式计数,并取两位小数   
System.out.println(new DecimalFormat("#.##%").format(pi));// 314.16%   
 
long c = 299792458;
 
// 显示为科学计数法,并取五位小数   
System.out.println(new DecimalFormat("#.#####E0").format(c));// 2.99792E8   
 
// 显示为两位整数的科学计数法,并取四位小数   
System.out.println(new DecimalFormat("00.####E0").format(c));// 29.9792E7   
 
// 每三位以逗号进行分隔。   
System.out.println(new DecimalFormat(",###").format(c));// 299,792,458   
 
// 将格式嵌入文本   
System.out.println(new DecimalFormat("光速大小为每秒,###米。").format(c));

bookmarks

Java在Web开发语言上败给了PHP

PHP的主要语言开发者之一、Zend公司的创始人之一Andi Gutmans最近在blog中直言不讳地批评了Java语言。他指出,目前Java厂商试图在JVM上提供动态语言实现的路子根本不对,Java已经输掉了Web开发语言的战争,网络营销培训PHP是事实上的标准和胜利者。

Gutmans的这篇文章在技术界引发了强烈争议,很对人对此有不同的意见,我在这里就阐述一下我对PHP和Java两种语言的看法。

我早先曾经在《Perl、PHP、ASP、JSP技术比较》一文中对比过PHP和Java的异同,简而言之,PHP是一种解释执行的脚本语言,语法和C语言类似,易学易用,不懂电脑的非专业人员稍经学习也能使用PHP.而Java要先编译成Class文件,然后在Java虚拟机上执行,Java开发需要熟悉Java语法以及一些核心的架构,从而实现一种可复用的、跨平台的软件,Java比PHP要难学的多。

实际上,从技术架构来说,Java语言相比PHP有明显的优势,Java使用的是面向对象的系统设计方法,而PHP还是采用面向过程的开发方法。PHP只能实现简单的分布式两层或三层的架构,而JAVA可以实现多层架构。数据库层(持久化层)、应用(业务)逻辑层、表示逻辑层彼此分开,而且现在不同的层都已经有一些成熟的开发框架的支持。例如Struts就是利用Java的web开发技术实现了MVC的设计模式,而在业务逻辑层也有Spring框架,数据库持久化层有Hibernate等框架。这些框架可以方便开发者高效、合理、科学得架构多层的商业应用。从数学运算和数据库访问速度来讲,Java的性能也优于PHP.实际上,对于跨平台的大型的企业应用系统来讲,Java几乎已经成为唯一的选择(微软.NET不支持跨平台),但是在于Web网站应用开发来讲,Java却面临着被PHP边缘化的危险,几乎所有的虚拟主机都支持PHP+MySQL,而支持Java的却少之又少,在资源上,网上有不计其数的PHP资源,很多著名的大型网站(例如Facebook、Mediawiki等)都是基于PHP的,而成功的Java网站却寥寥无几,这又是什么原因呢?

Java的理念是“一次编写,到处运行”,Java在应用框架底下的架构是无与伦比的,远胜过其他任何语言,Java的框架利于大型的协同编程开发,系统易维护、可复用性较好。而PHP很容易自学,让热备能快速简洁地编写代码,适合于快速开发,中小型应用系统,开发成本低。在调试、发布上,PHP也较Java简单。

理念上的不同导致了Java和PHP在Web应用开发上显示了不同的结果,尽管Java的数学计算和数据库访问都有优势,架构也相当完美,但是PHP却可以简单轻松地支持高强度Web访问,能够快速开发应用,支持PHP的虚拟主机多如牛毛,使得用PHP开发一个网站比用Java开发一个网站要快得多,容易的多。Java所拥有的优点只适合传统的以软件项目为核心的开发模式,而PHP更适合于以客户为核心的SaaS的开发模式,因此,PHP目前在Web网站开发的优势完全是因为Web网站开发的特殊性而导致的,并非编程语言特性所决定。

因此,PHP在Web网站开发语言的战争中已经慢慢将Java抛在了后面,Java要想在Web网站开发上奋起直追,的确应该多听听Andi Gutmans的意见,彻底改变一下思路才行,否则两者的差距只能是越来越远。

另外,虽然网络营销培训在国际上LAMP(Linux+Apache+Mysql+Php)架构已经占领了统治地位,但是在中国国内还有一个怪胎,就是基于微软的Windows Server+IIS+SqlServer+ASP/ASP.NET的架构,从理论上说,微软的这一套架构也能实现不错的性能,只可惜Windows和SqlServer价格不菲,整个架构在性能上比起LAMP不仅没有什么优势,反而还有不少劣势,因此微软的这一套家伙在国际市场上吃不开。而国内使用微软盗版则可以忽略成本,而ASP的易学易用性不逊于PHP,甚至连IT外行都能够使用,因此在国内也有不小的市场。但是随着中国在保护知识产权方面的日趋完善,免费的LAMP依旧是未来的趋势。(fblww-0120)

61条Java面向对象设计的经验原则

(1)所有数据都应该隐藏在所在的类的内部。

(2)类的使用者必须依赖类的共有接口,但类不能依赖它的使用者。

(3)尽量减少类的协议中的消息。

(4)实现所有类都理解的最基本公有接口[例如,拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等].

(5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。

如果类的两个方法有一段公共代码,那么就可以创建一个防止这些公共代码的私有函数。

(6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。

(7)类之间应该零耦合,或者只有导出耦合关系。也即,一个类要么同另一个类毫无关系,要么只使用另一个类的公有接口中的操作。

(8)类应该只表示一个关键抽象。

包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生影响,而对其他的包不造成任何影响 .(9)把相关的数据和行为集中放置。

设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。

(10)把不相关的信息放在另一个类中(也即:互不沟通的行为)。

朝着稳定的方向进行依赖。

(11)确保你为之建模的抽象概念是类,而不只是对象扮演的角色。类应当统一地共享工作。

(13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。

规划一个接口而不是实现一个接口。

(14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。

(15)对包含太多互不沟通的行为的类多加小心。

这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。

(16)在由同用户界面交互的Java面向对象模型构成的应用程序中,模型不应该依赖于界面,界面则应当依赖于模型。

(17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) .(18)从你的设计中去除不需要的类。

一般来说,我们会把这个类降级成一个属性。

(19)去除系统外的类。

系统外的类的特点是,抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。

(20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类,特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。

(21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段,我们常会发现很多代理没有用的,应当去除。

(22)尽量减少类的协作者的数量。

一个类用到的其他类的数目应当尽量少。

(23)尽量减少类和协作者之间传递的消息的数量。

(24)尽量减少类和协作者之间的协作量,也即:减少类和协作者之间传递的不同消息的数量。

(25)尽量减少类的扇出,也即:减少类定义的消息数和发送的消息数的乘积。

(26)如果类包含另一个类的对象,那么包含类应当给被包含的对象发送消息。也即:包含关系总是意味着使用关系。

(27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。

(28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6.当类包含多于6个数据成员时,可以把逻辑相关的数据成员划分为一组,然后用一个新的包含类去包含这一组成员。

(29)让系统功能在窄而深的继承体系中垂直分布。

(30)在实现语义约束时,最好根据类定义来实现。这常常会导致类泛滥成灾,在这种情况下,约束应当在类的行为中实现,通常是在构造函数中实现,但不是必须如此。

(31)在类的构造函数中实现语义约束时,把约束测试放在构造函数领域所允许的尽量深的包含层次中。

(32)Java面向对象中,约束所依赖的语义信息如果经常改变,那么最好放在一个集中式的第3方对象中。

(33)约束所依赖的语义信息如果很少改变,那么最好分布在约束所涉及的各个类中。

(34)类必须知道它包含什么,但是不能知道谁包含它。

(35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。

(36)继承只应被用来为特化层次结构建模。

(37)派生类必须知道基类,基类不应该知道关于它们的派生类的任何信息。

(38)基类中的所有数据都应当是私有的,不要使用保护数据。

类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。

(39)在理论上,继承层次体系应当深一点,越深越好。

(40)在实践中,继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6.(41)所有的抽象类都应当是基类。

(42)所有的基类都应当是抽象类。

(43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。

(44)如果两个或更多个类共享公共数据(但没有公共行为),那么应当把公共数据放在一个类中,每个共享这个数据的类都包含这个类。

(45)如果两个或更多个类有共同的数据和行为(就是方法),那么这些类的每一个都应当从一个表示了这些数据和方法的公共基类继承。

(46)如果两个或更多个类共享公共接口(指的是消息,而不是方法),那么只有他们需要被多态地使用时,他们才应当从一个公共基类继承。

(47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下,设计者应当使用多态。

(48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构,每个属性值都被变换成一个派生类。

(49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类型。

(50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。

(51)如果你觉得需要在运行时刻创建新的类,那么退后一步以认清你要创建的是对象。现在,把这些对象概括成一个类。

(52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。

(53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。

(54)在创建继承层次时,试着创建可复用的框架,而不是可复用的组件。

(55)如果你在设计中使用了多重继承,先假设你犯了错误。如果没犯错误,你需要设法证明。

(56)只要在Java面向对象设计中用到了继承,问自己两个问题:(1)派生类是否是它继承的那个东西的一个特殊类型?(2)基类是不是派生类的一部分?

(57)如果你在一个面向对象设计中发现了多重继承关系,确保没有哪个基类实际上是另一个基类的派生类。

(58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择,请选择包含关系。

(59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。

(60)Java面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是,在对逻辑设计作出决策的过程中我们经常用到物理设计准则。

(61)不要绕开公共接口去修改对象的状态。

Java的辉煌,还能延续多久?

Oracle对Sun的收购引发了人们对Java未来的一丝担心,Oracle能否继续保持Java的开放性,面对Ruby、Python或PHP等一批轻量型语言的崛起,Java能否继续保持其在开发领域的领导地位?

14年前,Sun公司的一位营销天才把一门试验性的跨平台语言由象征踏实的Oak(橡树),改名为香气四溢的Java(咖啡)时,可能他没有想到这门语言能有后来的辉煌。事实上,如果现在Sun想为这门语言改名,以准确体现其在计算机行业的地位,似乎Oak更形象。今天,虽然Java语言并非真正意义上的遍地开花,但它已经出现在众多场合和设备中,而且它享有运行稳定、设计精良的美名;Java代码也许无法主导所有计算机或所有平台,但它离成为通用语言已近在咫尺。 Java之父詹姆斯戈斯林(JamesGosling)在Oracle主办的OpenWorld大会上登台发言时阐述了这一点。他调出JavaFX幻灯片,上面是一连串统计数字:超过8.5亿个具有Java功能的桌面机和大约100亿个具有Java功能的设备。实际上,Java虚拟机在电子设备中司空见惯:电子书阅读器Kindle、蓝光磁盘播放机和智能电话(包括不太智能的手机)等。iPhone(手机上网)应用程序可以在成千上万部iPhone上运行,但Java嵌入在26亿部手机上,从不太智能、20美元就能买到的手机,到最新一代的黑莓和Android手机无一不包。 请戈斯林到OpenWorld大会上演讲,只是Oracle掌门人拉里埃利森(LarryEllison)希望向工程师们一再保证这门语言前途光明的手段之一。Oracle想要并购Sun,但它仍得等待欧洲监管部门批准这一决策。美国政府已开了绿灯,但欧洲政府官员由于担心MySQL的发展还没有同意这一起交易。戈斯林和Sun董事长麦克尼利(McNealy)都表示,一旦并购工作完成,Java会从Oracle得到比以往更多的关注和资源。 从近期来看,埃利森传达的信号也许不是很重要,因为如今Java已成气候,要改变发展方向也并不容易。当然,也有一些人认为,Oracle的商业模式太不一样了,所以它必然会对Java生态系统的每个部分进行重大变化。总体来说,每拿出一个Java可能变化的理由,就有同样充足的理由表明Oracle可能还是希望保持现状。

企业级应用是主战场

Java最先在服务器端找到了自己的位置,未来这个领域仍是有望看到Java虚拟机的主要地方。对Oracle的所有产品来说,大型服务器也是主要的安身之处,所以出现这对组合自在情理当中。虽然PHP编程员青睐MySQL,但对数据密集型的企业应用来说,许多最要紧的项目还是使用基于Oracle的架构封装而成的Java,这种情况应该不会很快发生变化。 Sun称,GlassFish应用服务器每个月的下载量超过100万人次,Tomcat等比较旧的平台仍然很常见。由于Java这项技术备受推崇、运行速度快、真正跨平台,大型企业(如银行和保险公司)对Java开发人员求之若渴。 不过,Java不再被认为是最新最酷的语法。一些编程员对静态类型语言的结构满腹牢骚,纷纷改用更新颖或更简单的语言,比如Ruby、Python或PHP。现在许多较简单的Web应用程序就是用这些语言开发而成的,因为它们编写的代码容易修改,能快速建立原型。然而,这些使用便捷的新语言常常离不开Java:Ruby开发人员常常使用JRuby(基于Java实现的Ruby语言),因为Java虚拟机能够更出色地处理繁重任务、释放多个线程。Jython(基于Java实现的Python语言)也相似。 Java现在正在加入一些最新的编程技术,以此遏制这些新语言大举入侵。Grails明显模仿了Ruby onRails的许多简单的说明性模式;Grails这种框架利用名为Hibernate的数据库中间件,把Groovy等脚本插件结合起来。Groovy本身添加了众多的动态选项便于代码解释,同时可以直接链接至Java应用编程接口(API)的任何部分。甚至不需要考虑Python或Ruby,因为Groovy凭借一种精巧、现代的语法,让Java编程员可以使用似乎变化无穷的庞大库和底层稳若磐石的虚拟机。

走上移动之路

Java手机的数量(估计约26亿部)委实惊人,因为市面上许多最简单的手机里面都运行Java平台微型版(Java ME)。这让Wattpad.com等公司得以构建在整个第三世界都能顺畅运行的文档阅读平台。 不过,运行Java的智能电话数量相对少一点。iPhone的巨大成功激励许多人重新学习ObjectiveC,这门语言让编程员对于内存使用等一些系统问题提高了控制能力。Java为编程员隐藏了大部分底层问题,这是个优点,但前提是不需要管理内存等资源,因为要是垃圾收集出现一个小失误,有些游戏就运行不了。可遗憾的是,因为电池续航时间是极其重要的一个因素,智能电话需要比几乎其他任何平台更严格的资源管理。 不过,Java编程员仍然很吃香,因为黑莓手机在其新平台上继续采用JavaME:它为手机的情景模式(profile)添加了支持触摸屏和方向感应器的功能。而Android存在不可预知的因素。由于谷歌开放了Android的使用,许多手机厂商搭上Android这辆彩车。 谷歌的Android建立在开源Apache Harmony及其类上,而不是建立在Sun开发的Java开发工具包(JDK)和JavaME上。对使用Eclipse编写代码的人来说,它们看上去几乎一模一样。在其他许多情况下也无关紧要,因为Android开发使用了很多XML表单,但如果这两套开发框架离对方渐行渐远,这种分裂可能会变成大问题。

收复桌面阵地

大多数人仍然认为Java在桌面端从来没有取得成功,这是过去。如今,Java正在缓慢而稳步地渗入到现代操作系统的各个角落。虽然用Swing编写的标准应用程序因试图定位在每个平台的最基本部分而继续遭殃,但是有了像JavaFX和WebStart这些比较新的开发平台和框架,就有可能通过Web有效地部署软件。本地平台可处理Java归档(JAR)的所有缓存工作。只要点击链接,有时偶尔随后点击几下授予权限的对话框,软件就可以安装及更新,还可以随时运行。 JavaFX仍然是一个名副其实的未知因素。图形功能现在可与Adobe的Flash相竞争;计算引擎可支持大部分的JavaAPI,但这门语言是一门奇怪的混合语言,融合了正宗Java、JavaScript及其他的一些标记语言。其代码比正规的Java简单,所以Java编程员又要学习新的东西。不过,对极具互动性的桌面工具而言,新的动画类也许值得花时间学习。WebStart正在继续慢慢改进通过浏览器直接把软件部署到桌面的功能。

抢占嵌入式领域

Java还在人们最预料不到的地方茁壮成长。虽然C编程人员可能从来不会承认Java虚拟机巧妙处理存储区、快速运行的功能,但Java在非智能手机、机顶盒、嵌入式芯片、Kindle及其他低功耗设备取得的成功表明:Java虚拟机完全有能力在嵌入式应用方面一展身手。Java的普及性还帮助编程人员从大平台迁移到小平台。虽然为大型机开发企业级应用软件改成开发小型嵌入式代码并不简单,但Java标准大大简化了这种转变,这让其他许多工具自叹弗如。 Java程序包也在变得越来越小巧。戈斯林用尘埃来形容一台硬币大小、能够识别Java的计算机。JavaCard是面向这类小型程序包的一种虚拟机和API,它即将迎来3.0版,这个里程碑式版本将增添网络连接功能。尽管这些小不点还没有小得足以放入到人的眼睛中,但直接与互联网通话的功能却让它们显得极具诱惑力。

合作伙伴会分道扬镳?

所有开发人员的最大担心是:要是Oracle收购Sun的交易尘埃落定,会出现什么样的利益冲突变化?Oracle是靠收取大笔的软件许可费成长壮大,其软件可运行在客户想要购买的任何硬件上。而另一方面,Sun通常是免费赠送软件,然后通过销售服务器赚到一些钱。这些经销策略也许不会立即发生变化,因为惯性实在太太了,但谁也不知道将来Oracle会做出怎样的决策。 一些人认为,Oracle过去在收取大笔许可费方面屡试不爽,只会鼓励埃利森对Sun采取类似的手法。也许Oracle的销售团队眼下就在垂涎这个机会:针对Java以前免费的地方开始逐步提高许可费。为了避免重新编写Java平台企业版(JavaEE)应用软件,许多企业很可能宁可支付每个CPU 100美元、200美元甚至100万美元的费用。 批评人士指出,Oracle很容易开发出新版Java虚拟机,针对不同的市场推出不同的性能级别。桌面虚拟机可能保持免费,Oracle甚至可能会掏钱请电脑厂商来推销Java和JavaFX,而处理极限多线程方面的性能改进可能会收取非常高的费用。从用户身上捞钱有好多法子,许可费相比之下往往便宜得多:要是让拒不服从的编程员先学习一门新语言,然后重新编写代码库,那成本高多了。 但也有人认为,Oracle也许不会采用这一招。一名接近Sleepycat(这家开源数据库公司在2006年被Oracle收购)的消息人士表示,Oracle已把技术队伍的规模扩大了约一倍,而所有双许可模式原封不动。软件仍然采用开源或商业许可证这两种形式。如果Oracle像Sleepycat那样对待Java,社区许可及其他方案仍然会跟以前一样免费、随处可得,同时有更多的工程师来改进代码。 与其他各大Java合作伙伴的长期关系方面仍存在更深层的问题。谷歌继续支持ApacheHarmony,这个代码超过125万行的项目似乎一心要破坏Sun作为世界中心的地位。IBM输掉了争夺Sun的竞标战,现在发现竞争对手Oracle的实力更强劲了。IBM设计了Eclipse开发工具,可能也会开始把Java平台带往另一个方向。 其他合作伙伴的态度比较激烈。SAP公司首席技术官VishalSikka一再要求Sun发布Java社区进程(JCP),着重提到了Oracle在2007年提出的方案:将控制权交由一家开放、独立、与厂商中立的标准组织,标准组织的所有成员在机会均等的前提下参与。虽然Oracle对相关细节基本保持缄默,但可以认为,这家公司会因为从Sun承袭过来的一些观点而重新赢得尊重。 但是,尽管其他合作伙伴可能会参与恫吓的举动,但他们可能会考虑度的问题,因为大家其实是相互牵制的,任何过激的行为都极可能会被阻止,因为大家都认识到一次编写、到处运行理念具有的优势。如果为Android手机编写的代码无法很容易地迁移至索尼蓝光播放机或Glassfish服务器,另一门语言就有机会应运而生。实际上已经有多家公司在编写工具包,让用户可以在iPhone上轻松运行Ruby on Rails或Python软件。 另外,许多这些比较新的语言可能会成为不可小觑的竞争对手,而暗斗过多只会帮助它们攻城掠地。现在有几十种非常好、知名度小一点的开源程序包,只要忠实的爱好者稍加转换,通常就能把它们移植到每个平台上。比如,Python已经是一些科学领域的主要语言,谷歌选择Python、而不是Java作为其应用引擎(AppEngine)支持的第一种语言。虽然IBM、Oracle和谷歌在争夺主导权的竞争中可能会相互排挤,但它们必须认识到:所有人都受益于标准化,而不是垄断。要是谁敢过于排挤别人、企图一手控制Java,其他厂商可能会奔向其竞争对手。

Java也开应用程序商店?

Java代码库仍相当有凝聚力、相对标准化,这个事实惹得众人猜测:Sun(如果合并案完成,还有Oracle)到底会怎样利用Java的普及性来大发其财,又不提高许可费、挤压每个人?如果有人开发出一种面向整个Java生态系统的应用程序商店(AppStore),从而像销售面向iPhone的应用程序那样销售用Java编写的小组件(widget)它们可以在桌面、手机、蓝光播放机或可以使用Java的其他任何平台上运行,将会怎么样? 最近已经有了面向Android手机的一批数量可观的应用程序,Sun也在谋划一家Java商店,好让人们只需把应用程序拖到桌面上,或者只要再编一点代码,就可以把各应用程序结合起来,从而让它们可以在Java世界的几乎每个角落里运行。不过,处理截然不同的屏幕和用户界面还是个挑战。 设想一下这种场景有多吸引人:开发人员编写的某个应用程序在Android手机上运行着,他在办公桌面上处理任务,回到家后在客厅的蓝光播放机上顺畅运行。

把Java应用程序带到坐沙发的人面前甚至有点出人意料,因为Java这门语言在被叫做Oak的早期阶段,本意就是运行在机顶盒上。这种远景将依赖于Java平台的最大优点:普及性和跨平台的稳定性,也许这些优点会帮助Java给其发明者带来滚滚收入。

收藏

http://www.javacoder.cn