Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, May 18, 2016

Centos how to config JAVA_HOME

This tutorial describes how to install and configure latest Oracle Java JDK on CentOS 7, 6.5, and 6.4 servers. Although, the steps should work on other RPM based distributions such as RHEL 7, 6.x, Scientific Linux 6.x, and Fedora too.
First of all, update your server.
yum update
Then, search for if any older JDK versions are installed in your system.
rpm -qa | grep -E '^open[jre|jdk]|j[re|dk]'
Sample output:
gobject-introspection-1.36.0-4.el7.x86_64
pygobject3-base-3.8.2-4.el7.x86_64
To check the already installed Java version, enter the following command:
java -version
If Java 1.6 or 1.7 have been installed already, you can uninstall them using the following commands.
yum remove java-1.6.0-openjdk
yum remove java-1.7.0-openjdk

Download And Install Oracle Java JDK

At the time of writing this tutorial, the latest Java JDK version was JDK 8u25. First, let us download the latest Java version.
Go to the Oracle Java download page and download the required version depending upon your distribution architecture.
As I use 64bit CentOS 7 server, I have downloaded the 64bit rpm package.
Then, go to the directory where you’ve downloaded the jdk package, and run the following command to install it.
rpm -ivh jdk-8u25-linux-x64.rpm
Sample output:
Preparing...                          ################################# [100%]
Updating / installing...
   1:jdk1.8.0_25-2000:1.8.0_25-fcs    ################################# [100%]
Unpacking JAR files...
    rt.jar...
    jsse.jar...
    charsets.jar...
    tools.jar...
    localedata.jar...
    jfxrt.jar...

Check Java version

Now, check for the installed JDK version in your system using command:
java -version
Sample output:
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
As you see above, latest java 1.8 has been installed.

Setup Global Environment Variables

We can easily set the environment variables using the export command as shown below.
export JAVA_HOME=/usr/java/jdk1.8.0_25/
export PATH=$PATH:$JAVA_HOME
Now, let us check for the environment variables using commands:
echo $JAVA_HOME
Sample output:
/usr/java/jdk1.8.0_25/
Or
echo $PATH
Sample output:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/java/jdk1.8.0_25/
However, the above method is not recommended. Because, the path will be disappeared when the system reboots. To make it permanent, you have to add the paths in the system wide profile.
To do that, create a file called java.sh under /etc/profile.d/ directory.
vi /etc/profile.d/java.sh
Add the following lines:
#!/bin/bash
JAVA_HOME=/usr/java/jdk1.8.0_25/
PATH=$JAVA_HOME/bin:$PATH
export PATH JAVA_HOME
export CLASSPATH=.
Save and close the file. Make it executable using command:
chmod +x /etc/profile.d/java.sh
Then, set the environment variables permanently by running the following command:
source /etc/profile.d/java.sh
That’s it.

What if I didn’t remove the old JDK versions from my system?

As I mentioned before, make sure you have removed all old JDK versions from your system. If you didn’t remove the older versions from your server before installing latest JDK version, you should tell your system from where java should be executed.
By default, the JDK 1.8.x will be installed in /usr/java/jdk1.8.0_25/ location. In order to tell our system, from where java should be executed, we need to run the following commands one by one.
alternatives --install /usr/bin/java java /usr/java/jdk1.8.0_25/jre/bin/java 20000
alternatives --install /usr/bin/jar jar /usr/java/jdk1.8.0_25/bin/jar 20000
alternatives --install /usr/bin/javac javac /usr/java/jdk1.8.0_25/bin/javac 20000
alternatives --install /usr/bin/javaws javaws /usr/java/jdk1.8.0_25/jre/bin/javaws 20000
alternatives --set java /usr/java/jdk1.8.0_25/jre/bin/java
alternatives --set jar /usr/java/jdk1.8.0_25/bin/jar
alternatives --set javac /usr/java/jdk1.8.0_25/bin/javac 
alternatives --set javaws /usr/java/jdk1.8.0_25/jre/bin/javaws
All done. Let us check the alternatives.
ls -lA /etc/alternatives/
Sample output:
lrwxrwxrwx. 1 root root 29 Dec  2 16:24 jar -> /usr/java/jdk1.8.0_25/bin/jar
lrwxrwxrwx. 1 root root 34 Dec  2 16:24 java -> /usr/java/jdk1.8.0_25/jre/bin/java
lrwxrwxrwx. 1 root root 31 Dec  2 16:24 javac -> /usr/java/jdk1.8.0_25/bin/javac
lrwxrwxrwx. 1 root root 36 Dec  2 16:24 javaws -> /usr/java/jdk1.8.0_25/jre/bin/javaws
[...]
That’s it. Now check for the java version using command:
java -version
Sample output:
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)





Thanks To:
http://www.unixmen.com/install-oracle-java-jdk-8-centos-76-56-4/

Thursday, May 12, 2016

Java运行时如何开辟内存空间的?

为什么会出现OOM?
你了解JVM是如何分配内存空间的吗?
Static 是如何进驻内存的?
JVM对方法区的大小有限制吗?
对于堆和栈,除了是保存对象和引用,JVM 对于他们有限制吗?
java  静态方法存放在哪里?

你考虑过上面的问题吗?


JVM运行时数据区分类

程序计数器 (Program Counter (PC) Register)
JVM栈 (Java Virtual Machine Stacks)
堆内存 (Heap Memory)
方法区 (Method Area)
运行时常量池 (Run-time Constant Pool)
本地方法栈 (Native Method Stacks)


有图有真相:


按线程持有划分

查看上面的图,可以得知以上六个数据区其实线程私有还是共享,可以分为如下两种。

单个线程私有(Managed Per-Thread) 属于这一种的数据区包含 程序计数器, JVM栈还有本地方法栈。 每个线程都私有这三个数据区,这些数据区在其所属的线程创建时初始化,并随着所属线程结束被销毁。

多个线程共享 属于这一种的数据区包含 堆内存,方法区和运行时常量池。这些数据区可以被每一个线程访问,他们随着JVM启动而初始化,同时伴随JVM关闭而销毁。
程序计数器

在通用的计算机体系中,程序计数器用来记录当前正在执行的指令,在JVM中也是如此。程序计数器是线程私有,所以当一个新的线程创建时,程序计数器也会创建。由于Java是支持多线程,Java中的程序计数器用来记录当前线程中正在执行的指令。如果当前正在执行的方法是本地方法,那么此刻程序计数器的值为undefined。注意这个区域是唯一一个不抛出OutOfMemoryError的运行时数据区。

JVM栈

在介绍JVM栈之前,简单介绍一个概念,栈帧

栈帧

一个栈帧随着一个方法的调用开始而创建,这个方法调用完成而销毁。栈帧内存放者方法中的局部变量,操作数栈等数据。

JVM栈只对栈帧进行存储,压栈和出栈操作。栈内存的大小可以有两种设置,固定值和根据线程需要动态增长。在JVM栈这个数据区可能会发生抛出两种错误。

StackOverflowError 出现在栈内存设置成固定值的时候,当程序执行需要的栈内存超过设定的固定值会抛出这个错误。
OutOfMemoryError 出现在栈内存设置成动态增长的时候,当JVM尝试申请的内存大小超过了其可用内存时会抛出这个错误。

堆数据区

堆数据区是用来存放对象和数组(特殊的对象)。堆内存由多个线程共享。堆内存随着JVM启动而创建。众所周知,Java中有一个很好的特性就是自动垃圾回收。垃圾回收就操作这个数据区来回收对象进而释放内存。如果堆内存剩余的内存不足以满足于对象创建,JVM会抛出OutOfMemoryError错误。

方法区

在JVM规范中,方法区被视为堆内存的一个逻辑部分。这一点可能由于具体的JVM实现而不同,甚至在方法区不实现垃圾回收处理也是可以的。方法区和堆内存一样被多个线程访问,方法区中存放类的信息,比如类加载器引用,属性,方法代码和构造方法和常量等。当方法区的可用内存无法满足内存分配需求时,JVM会抛出OutOfMemoryError错误。

运行时常量池

运行时常量池创建在方法区,当一个类或者一个接口被创建的时候,JVM会创建一个运行时常量池。一个运行时常量池实际上是一个类或者接口的class文件中常量池表(constant_pool table)的运行时展示形式。一个运行时常量池包含了多种类型的常量,从诸如运行时可以确定的数值型字面量到运行时才能决定的方法和属性引用。当运行时常量池无法满足于内存分配需求时,JVM会抛出OutOfMemoryError错误。

本地方法栈

一个支持native方法调用的JVM实现,需要有这样一个数据区,就是本地方法栈,Java官方对于本地方法的定义为methods written in a language other than the Java programming language,就是使用非Java语言实现的方法,但是通常我们指的一般为C或者C++,因此这个栈也有着C栈这一称号。一个不支持本地方法执行的JVM没有必要实现这个数据区域。本地方法栈基本和JVM栈一样,其大小也是可以设置为固定值或者动态增加,因此也会对应抛出StackOverflowError和OutOfMemoryError错误。


=======================

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄。


堆  主要是用来存储对象的
栈  主要是用来执行程序的





Thanks to:






Wednesday, May 11, 2016

代码重构的感悟

随着自己的能力的不断的增长,主要是自己的视野和格局在不断的增长。让自己,觉的现在的代码越来越垃圾了,急需重构代码。项目中的冗余代码越来越多,这是为什么呢?这是因为,之前开发规范的问题。没有一个很好的规范,导致了各种问题,当然也埋下了很多的坑!

这么说,一个六个人的团队,未必就会比一个人的做的好!因为,In China 很多的时候,我们往往只相信自己的能力,并不相信别人。总觉的被人是傻逼。一般的只要不是大公司,小公司也包括中型的公司,新人到了公司之后,缺少代码规范的训练。因为,似乎每个人都很忙,他们不知道,现在的很忙,导致了以后会更忙。新人,必须要代码规范。但是,很多初级的程序员,往往没有这种意识!需要我们来督促!

说说,今天! 今天上午发了包,下午有点自己的时间,可以让自己来重构自己的代码!说真的我很庆幸现在自己的状态,因为,我算是 天时  地利  人和。 我很是庆幸,比如我的哥们,小强,他作为一个新人刚到公司,看到公司垃圾的代码,但是,他不可以重构,因为,作为新人,到了公司没有什么话语权。这个社会就是这个样子的,新人要有新人的样子。就像PM 很多都是傻逼,娜姐除外。说白了,很多人根本就是看不起程序员,我们一般是比较理想化的人,活在自己的世界里面,感觉自己的世界里面,自己似乎可以做所有的事情!说白了,我就是自己的神。总之,我现在重构我的代码,没有意思的顾虑,就是只要自己有时间就好了!花点精力来做这件事情。我觉的代码就像自己的老婆一样,如果,你都不花心思来整理,还有谁会对你的代码上心呢?所以,代码可以变的更好,实现 可修改,可维护,可增量!

这个世界上的事情,需求是不断的改变的。假如 需求是死的,那么的你活着还有什么意思!
我们就生活在不断变化 的世界里面

下面说说我的重构代码的感悟:

1 命名规范
这个问题,真是很蛋疼呢?说白了,很多人写代码就是瞎鸡巴写,根本就不在谁来维护代码,只要代码实现了就好,什么有道词典,百度呀,google 翻译呀,瞎鸡巴乱搞,很快他们就实现了功能,老板很开心,因为,很快就看到了产品,在老板的心里面,产品的代码应该是整整齐齐的。但是,在程序猿的心里面代码是乱七八糟的,我说的是大多数的。作为,刚到公司的人急于表现自己的能力,想让自己的能力得到老板的肯定。然后,就瞎鸡巴揽活,拿到需求之后,看到产品原型图,就瞎鸡巴写,写了之后发现有问题,就开始瞎鸡巴改!真是蛋疼的狠!最后,发现 坑越来越多,自己的坑越来越多,这是一个量变促进质变的过程。到了最后,发现自己真的是改不动bug了!然后,递交了辞职信!   这尼玛就是坑货, 新来的人  又开始了死循环!

解决:
命名规范的问题,每种语言都有自己的特性,但是命名确实大同小异。你需要根据自己的习惯总结一套自己的命名规范。不是每个人都有这种意识,很庆幸,我有这种意识!这个东西,CTO 产品经理 可以制订一份文档,来规范用到的英文。没有在文档汇总的,程序员可以  google,添加到文档中!

命名的规范有很多,我就不介绍了,你们随便找找吧!

2  Utils
为什么要提取Utils
今天,我的项目中用到了ImageLoader.  DisPalyOptions 很多地方都初始化了,将近 100 多个地方都用自己重新定义了一下!这样的重复代码, 根本原因,我们开发的时候,很多的时候只会粘贴复制。粘贴复制到了 代码的重复!

我的原则:  重复的地方超过了3次以上,立马听一下工作开始重构代码,或者提取到工具类!

我这里建立 了一个ImageLoaderUtils, 来处理 不同的DisplayOptions,  displayImage(). 

但是,这么做有什么好处呢?

我有一个问题,加入有一天,我不想用ImageLoader了,我想换一种 图片加载工具,比如 Passco 实现图片的加载。但是,现在的代码修改起来,代价太大了。因为内部代码跟ImageLoader 的耦合度太大了,属于低内聚,高耦合。就是,所有用到ImageLoader的地方都要修改。这样很不好。

这个时候,我体会到了解释器设计模式的用处。

提取工具类是一个非常好的习惯。因为,可以消重。消除重复代码的原则:拆分和抽取。就是 大事化小,小事化了,了事化无。

用了ImageLoaderUtils 之后,我可以在这个累的基础之上去使用适配器模式,做不同的  图片加载工具的 adapter. 我只需要链接不同的 图片加载的特性。然后,抽取一个 BaseImageLodaerUtil 设置几个抽象的方法,然后,让子类实现以下,就可以了!具体的需要思考。


这就是我今天的收获!


















Tuesday, January 5, 2016

Java 1.5 引入了泛型 generic

Java  版本的特性:

1  Java JDK1.5、1.6、1.7新特性整理




Java 1.5 引入了泛型 generic

<>  私人订制,  也是C++ 中的模板类型。

调高了代码的重用性和安全性


2  泛型的命名规范   

     为了更好地去理解泛型,我们也需要去理解java泛型的命名规范。为了与java关键字区别开来,java泛型参数只是使用一个大写字母来定义。各种常用泛型参数的意义如下:


  • E — Element,常用在java Collection里,如:           List<E>,Iterator<E>,Set<E>
  • K,V — Key,Value,代表Map的键值对
  • N — Number,数字
  • T — Type,类型,如String,Integer等等
  • S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样


    /**     *     * 第一、定义方法所用的泛型参数需要在修饰符之后添加,如上面的,public static <T>,如果有多个泛型参数,可如此定义<K,V>或者<T1,T2>。     *     * @param a     * @param c     */    public static <T> void fromArrayToCollection(T[] a,Collection<T> c){
        for (T t : a) {
            c.add(t);            //第二,不建议在泛型变量里添加其他类型,如下面的代码,将会引起编译错误(或隐含错误)//            c.add(new Object());        }
    }



2  泛型参数的界限   

    
上界和下界

 有时候,你会希望泛型类型只能是某一部分类型,比如操作数据的时候,你会希望是Number或其子类类型。这个想法其实就是给泛型参数添加一个界限

2.1 指定上界:    <T extends BoundingType>

当指定了上界的时候,所有 传入的数据类型都要是  指定类的子类,否则报错。问题,有一定的局限性。 相当与在这里 确定了最大的限度。

    接着引入下一个问题,如何为泛型参数添加多个限制范围,多重限制范围格式如下:
    <T extends A & B & C>
    一个泛型参数可以有多重限制范围,使用“&”分隔。且限制范围中之多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。举例如下:
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }

    如果BoundingType不是放在第一位,会产生编译异常:
class D <T extends B & A & C> { /* ... */ }  // 无法通过编译


2.2 指定下界:  <T super BoundingType>
 

3  泛型方法与泛参界限的整合

    如果说泛型方法是一个有用的工具,那泛参的界限就应该这个工具的灵魂,为这个工具添加了一些“行为准则。


















reference:



Monday, November 30, 2015

Timer 计时器

private void getAgentLocalInfo(){
    if(curTimer == null){
        curTimer = new Timer(true);    }

    curTimer.schedule(new java.util.TimerTask() {
        @Override        public void run() {
            startLocalInfo();        }
    }, 5000, 6 * 1000);}

/**
 * Schedule a task for repeated fixed-delay execution after a specific delay.
 *
 * @param task
 *            the task to schedule.
 * @param delay
 *            amount of time in milliseconds before first execution.
 * @param period
 *            amount of time in milliseconds between subsequent executions.
 * @throws IllegalArgumentException
 *                if {@code delay < 0} or {@code period <= 0}.
 * @throws IllegalStateException
 *                if the {@code Timer} has been canceled, or if the task has been
 *                scheduled or canceled.
 */
public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0 || period <= 0) {
        throw new IllegalArgumentException();
    }
    scheduleImpl(task, delay, period, false);
}



refence:
http://blog.csdn.net/mariofei/article/details/11686855

Tuesday, November 3, 2015

Java class 文件格式以及类加载器介绍


Java class 文件格式以及类加载器介绍
在后面的内容中,需要对 Java class 文件格式以及类加载器的知识有一定的了解,所以这里先对这些内容做一个简单介绍:
class 文件格式
Java class 文件的结构如图 2 所示(图中“*”表示出现 0 次或任意多次):
图 2.Java class 文件结构



详细说明如下:
Magic Number: 每个 class 文件的前 4 个字节被称为“魔数”,它的内容为:0xCAFEBABE。魔数的作用在于可以轻松地分辨出一个文件是不是 class 文件。

Version: 该项指明该 class 文件的版本号。

Constant Pool: 常量池是 class 文件中结构最为复杂,也最为重要的部分。常量池包含了与文件中类和接口相关的常量。常量池中存储了诸如文字字符串,final 变量值。Java 虚拟机把常量池组织为入口列表的形式。常量池中许多入口都指向其他的常量入口,而且 class 文件中紧随着常量池的许多条目也都会指向常量池的入口。除了字面常量之外,常量池还可以容纳以下几种符号引用:类和接口的全限定名,字段的名称和描述符和方法的名称和描述符等。

Modifiers: 该项指明该文件中定义的是类还是接口,以及声明中用了哪种修饰符,类或接口是私有的,还是公共的,类的类型是否是 final 的,等等。

This class: 该项是对常量池的索引。在这个位置,Java 虚拟机能够找到一个容纳了类或接口全限定名的入口。这里需要注意的是:在 class 文件中,所有类的全限定名都是以内部名称形式表示的。内部名称是将原先类全限定名中的“.”替换为“/”。例如:java.lang.String 的内部名称为 java/lang/String。

Super Class: 该项也是对常量池的索引,指明了该类超类的内部名称。

Interfaces: 该项指明了由该类直接实现或由接口扩展的父接口的信息。
注:Modifiers,This Class,Super Class 和 Interfaces 这四项的和就是一个类的声明部分。
Annotation: 该项存储的是注解相关的内容,注解可能是关于类的,方法的以及字段的。
Attribute: 该项用来存储关于类,字段以及方法的附加信息。在 Java 5 引入了注解之后,该部分内容几乎已经没有用处。

Field: 该项用来存储类的字段信息。

Method: 该项用来存储类的方法信息。

===================================================================

类装载器介绍

类装载器负责查找并装载类。每个类在被使用之前,都必须先通过类装载器装载到 Java 虚拟机当中。Java 虚拟机有两种类装载器 :
启动类装载器
启动类装载器是 Java 虚拟机实现的一部分,每个 Java 虚拟机都必须有一个启动类装载器,它知道怎么装载受信任的类,比如 Java API 的 class 文件。
用户自定义装载器
用户自定义装载器是普通的 Java 对象,它的类必须派生自 java.lang.ClassLoader 类。ClassLoader 类中定义的方法为程序提供了访问类装载机制的接口。


类装载器工作机制 

类装载器就是寻找类的节码文件并构造出类在JVM内部表示对象的组件。在Java中,类装载器把一个类装入JVM中,要经过以下步骤: 

[1.]装载:查找和导入Class文件; 
[2.]链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的: 
    [2.1]校验:检查载入Class文件数据的正确性; 
    [2.2]准备:给类的静态变量分配存储空间; 
    [2.3]解析:将符号引用转成直接引用; 
[3.]初始化:对类的静态变量、静态代码块执行初始化工作。

类装载工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件。JVM在运行时会产生三个ClassLoader:
根装载器、
ExtClassLoader(扩展类装载器)
AppClassLoader(系统类装载器)
1  根装载器不是ClassLoader的子类,它使用C++编写,因此我们在Java中看不到它,根装载器负责装载JRE的核心类库,如JRE目标下的rt.jar、charsets.jar等。
2  ExtClassLoader和AppClassLoader都是ClassLoader的子类。其中ExtClassLoader负责装载JRE扩展目录ext中的JAR类包;
3  AppClassLoader负责装载Classpath路径下的类包。


这篇博客 还不错:


===================================================================
附录:






泛型与多重继承的关系 Java getGenericSuperclass()和getActualTypeArguments()基本用法:




遇到的问题,在处理的时候 我提取了多次的 BaseActivity.  结构是这样子的
DetailQRcodeActivity  extends  BaseQRcodeActivity
BaseQRcodeActivity    extends  CaptureActivity
CaptureActivity            extends  BaseActivity<SingleControl>


private void controlInit() {
    Class<?> clazz;    clazz = mReferenceObj.getClass();    generateControl(clazz);    if (mControl == null) {
        generateControl(clazz.getSuperclass());    }
}

上面的处理方式:
1 mReferenceObj  是 DetailQRcodeActivity instance.  所以第一次调用 generateControl() 
之后 mControl == null.
2 mReferenceObj,getSuperClass()  直接父类。也就是 BaseQRcodeActivity,这个时候调用
generateControl()  因为BaseQRcodeActivity extends  CaptureActivity, 并没有泛型 的信息。也就是没有 SingleControl 类.
所以 此时  mControl  == null ,这是为什么呢? 原来是因为泛型在继承的时候 之影响到 她的直接子类的信息。也就是他只会影响到CaptureActivity,  而对于她的孙子 BaseQRcodeActivity,  自然就  心有余而力不足啦!解决方案也就出来了, 第一种方法只解决当前的问题,或者以后每次写这种多继承的时候,需要添加。 第二种方案 从根本上解决问题。 我喜欢第二种。 这是在关联的时候有解决!


So how to reslove this problem?
1  First way:
you  can follow this way

DetailQRcodeActivity  extends  BaseQRcodeActivity
BaseQRcodeActivity    extends  CaptureActivity< SingleControl >
CaptureActivity <? extends SingleControl >           extends  BaseActivity<SingleControl>

2 The second way:  you can do this way
private void controlInit() {
    Class<?> clazz;    clazz = mReferenceObj.getClass();    generateControl(clazz);    if (mControl == null) {
        generateControl(clazz.getSuperclass());    }
    if (mControl == null){
        generateControl(clazz.getSuperclass().getSuperclass());    }
}


in a world I love the second way, because 一劳永逸!


=======================================================

核心代码:
http://blog.csdn.net/hikvision_java_gyh/article/details/10182309


    private void generateControl(Class clazz) {
        //1 getGenericSuperclass() //通过反射获取当前类表示的实体(类,接口,基本类型或void)的直接父类的Type,
        //Type type = this.getClass().getGenericSuperclass();
        //是得到这个类的得到泛型父类
        Type type = clazz.getGenericSuperclass();

        //3 (type instanceof ParameterizedType)),这行代码的意思是
        // 如果没有实现ParameterizedType接口,即不支持泛型;
        if (type instanceof ParameterizedType) {
            ParameterizedType p = (ParameterizedType) type;

            //2 getActualTypeArguments()返回参数数组。
            //Type[] params = ((ParameterizedType) genType).getActualTypeArguments();这行代码的意思是,如果支持泛型,返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class,因为可能有多个,所以是数组。
            Type[] arrayClasses = p.getActualTypeArguments();

            for (Type item : arrayClasses) {
                if (item instanceof Class) {
                    Class<T> tClass = (Class<T>) item;
                    if (tClass.equals(BaseControl.class) || (tClass.getSuperclass() != null
                            && tClass.getSuperclass().equals(BaseControl.class))) {

                        // the same  deal with!
                        messageProxy = new MessageProxy(mHandler);
                        mControl = ControlFactory.getControlInstance(tClass,
                                messageProxy);
                        mModel = new ModelMap();
                        mControl.setModel(mModel);
                        return;
                    }
                }
            }
        }
    }




=======================================================


1.Class<? super T> getSuperclass():返回本类的父类
  注意: 这里获取的 父类是直接父类奥。这里的继承只有一层的时候是可以的!

2.Type getGenericSuperclass():返回本类的父类,包含泛型参数信息

=========================================

附加 参考链接:

http://blog.csdn.net/hikvision_java_gyh/article/details/10182309

http://blog.csdn.net/u010167086/article/details/15336259


Sunday, November 1, 2015

Java 集合之旅


世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合
有人想有可以自动扩展的数组,所以有了List
有的人想有没有重复的数组,所以有了set
有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree**

而几乎有有的集合都是基于数组来实现的.
因为集合是对数组做的封装,所以,数组永远比任何一个集合要快。

但任何一个集合,比数组提供的功能要多

一:数组声明了它容纳的元素的类型,而集合不声明。这是由于集合以object形式来存储它们的元素。

二:一个数组实例具有固定的大小,不能伸缩。集合则可根据需要动态改变大小。

三:数组是一种可读/可写数据结构---没有办法创建一个只读数组。然而可以使用集合提供的ReadOnly方法,以只读方式来使用集合。该方法将返回一个集合的只读版本。

==============================================================

MAP : INFO

/**
 * An object that maps keys to values.  A map cannot contain duplicate keys;
 * each key can map to at most one value.
 *
 * <p>This interface takes the place of the <tt>Dictionary</tt> class, which
 * was a totally abstract class rather than an interface.
 *
 * <p>The <tt>Map</tt> interface provides three <i>collection views</i>, which
 * allow a map's contents to be viewed as a set of keys, collection of values,
 * or set of key-value mappings.  The <i>order</i> of a map is defined as
 * the order in which the iterators on the map's collection views return their
 * elements.  Some map implementations, like the <tt>TreeMap</tt> class, make
 * specific guarantees as to their order; others, like the <tt>HashMap</tt>
 * class, do not.
 *
 * <p>Note: great care must be exercised if mutable objects are used as map
 * keys.  The behavior of a map is not specified if the value of an object is
 * changed in a manner that affects <tt>equals</tt> comparisons while the
 * object is a key in the map.  A special case of this prohibition is that it
 * is not permissible for a map to contain itself as a key.  While it is
 * permissible for a map to contain itself as a value, extreme caution is
 * advised: the <tt>equals</tt> and <tt>hashCode</tt> methods are no longer
 * well defined on such a map.
 *
 * <p>All general-purpose map implementation classes should provide two
 * "standard" constructors: a void (no arguments) constructor which creates an
 * empty map, and a constructor with a single argument of type <tt>Map</tt>,
 * which creates a new map with the same key-value mappings as its argument.
 * In effect, the latter constructor allows the user to copy any map,
 * producing an equivalent map of the desired class.  There is no way to
 * enforce this recommendation (as interfaces cannot contain constructors) but
 * all of the general-purpose map implementations in the JDK comply.
 *
 * <p>The "destructive" methods contained in this interface, that is, the
 * methods that modify the map on which they operate, are specified to throw
 * <tt>UnsupportedOperationException</tt> if this map does not support the
 * operation.  If this is the case, these methods may, but are not required
 * to, throw an <tt>UnsupportedOperationException</tt> if the invocation would
 * have no effect on the map.  For example, invoking the {@link #putAll(Map)}
 * method on an unmodifiable map may, but is not required to, throw the
 * exception if the map whose mappings are to be "superimposed" is empty.
 *
 * <p>Some map implementations have restrictions on the keys and values they
 * may contain.  For example, some implementations prohibit null keys and
 * values, and some have restrictions on the types of their keys.  Attempting
 * to insert an ineligible key or value throws an unchecked exception,
 * typically <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.
 * Attempting to query the presence of an ineligible key or value may throw an
 * exception, or it may simply return false; some implementations will exhibit
 * the former behavior and some will exhibit the latter.  More generally,
 * attempting an operation on an ineligible key or value whose completion
 * would not result in the insertion of an ineligible element into the map may
 * throw an exception or it may succeed, at the option of the implementation.
 * Such exceptions are marked as "optional" in the specification for this
 * interface.
 *
 * <p>Many methods in Collections Framework interfaces are defined
 * in terms of the {@link Object#equals(Object) equals} method.  For
 * example, the specification for the {@link #containsKey(Object)
 * containsKey(Object key)} method says: "returns <tt>true</tt> if and
 * only if this map contains a mapping for a key <tt>k</tt> such that
 * <tt>(key==null ? k==null : key.equals(k))</tt>." This specification should
 * <i>not</i> be construed to imply that invoking <tt>Map.containsKey</tt>
 * with a non-null argument <tt>key</tt> will cause <tt>key.equals(k)</tt> to
 * be invoked for any key <tt>k</tt>.  Implementations are free to
 * implement optimizations whereby the <tt>equals</tt> invocation is avoided,
 * for example, by first comparing the hash codes of the two keys.  (The
 * {@link Object#hashCode()} specification guarantees that two objects with
 * unequal hash codes cannot be equal.)  More generally, implementations of
 * the various Collections Framework interfaces are free to take advantage of
 * the specified behavior of underlying {@link Object} methods wherever the
 * implementor deems it appropriate.
 *
 * <p>Some map operations which perform recursive traversal of the map may fail
 * with an exception for self-referential instances where the map directly or
 * indirectly contains itself. This includes the {@code clone()},
 * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
 * Implementations may optionally handle the self-referential scenario, however
 * most current implementations do not do so.
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <K> the type of keys maintained by this map
 * @param <V> the type of mapped values
 *
 * @author  Josh Bloch
 * @see HashMap
 * @see TreeMap
 * @see Hashtable
 * @see SortedMap
 * @see Collection
 * @see Set
 * @since 1.2
 */

==============================================================

下面的链接是 HashMap实现原理:

HashMap的实现原理 (讲的不是很清晰)

==============================================================

HashMap  的数据结构: http://blog.csdn.net/vking_wang/article/details/14166593

look the picture:
pic 1

pic 2


HashMap put source:

1)put

疑问:如果两个key通过hash%Entry[].length得到的index相同,会不会有覆盖的危险?
  这里HashMap里面用到链式数据结构的一个概念。上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。所以疑问不用担心。也就是说数组中存储的是最后插入的元素。到这里为止,HashMap的大致实现,我们应该已经清楚了。


    /**
     * Maps the specified key to the specified value.
     *
     * @param key
     *            the key.
     * @param value
     *            the value.
     * @return the value of any previous mapping with the specified key or
     *         {@code null} if there was no such mapping.
     */
    @Override public V put(K key, V value) {
        if (key == null) {
            return putValueForNullKey(value);
        }

        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        int index = hash & (tab.length - 1);
        //1  如果key在链表中已存在,则替换为新value
        //  看了好一会儿,终于看明白了。这一过程是,当你新添加的元素 不仅 HashCode 一样。而且Key 也是一样的时候,就是 有重复的数据的时候 需要讲老的数据 替换,保证唯一性!
        for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
            if (e.hash == hash && key.equals(e.key)) {
                preModify(e);
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }

        // No entry for (non-null) key is present; create one
        modCount++;
        if (size++ > threshold) {
           //3  当你的 table[] 内存太小的时候就会调用该方法 分配更大的内存空间!
            tab = doubleCapacity();
            index = hash & (tab.length - 1);
        }
        //2  添加实体(其实是 zai'xiaindex替换下来的老的实体)
        // 这里才是真正的加入table[] 数据。 当你的HashCode 一样的时候,就调用这个方法。将老的数据的位置用新的数据替换, 老的数据后移一位!
        addNewEntry(key, value, hash, index);
        return null;
    }

    /**
     * Computes a hash code and applies a supplemental hash function to defend
     * against poor quality hash functions. This is critical because HashMap
     * uses power-of-two length hash tables, that otherwise encounter collisions
     * for hash codes that do not differ in lower or upper bits.
     * Routine taken from java.util.concurrent.ConcurrentHashMap.hash(int).
     * @hide
     */
    public static int secondaryHash(Object key) {
        return secondaryHash(key.hashCode());
    }

2 let me see:

    /**
     * Creates a new entry for the given key, value, hash, and index and
     * inserts it into the hash table. This method is called by put
     * (and indirectly, putAll), and overridden by LinkedHashMap. The hash
     * must incorporate the secondary hash function.
     */
    void addNewEntry(K key, V value, int hash, int index) {
        table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
    }

3  当你的 table[] 内存太小的时候就会调用该方法 分配更大的内存空间!
 /**
     * Doubles the capacity of the hash table. Existing entries are placed in
     * the correct bucket on the enlarged table. If the current capacity is,
     * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which
     * will be new unless we were already at MAXIMUM_CAPACITY.
     */
    private HashMapEntry<K, V>[] doubleCapacity() {
        HashMapEntry<K, V>[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            return oldTable;
        }
        int newCapacity = oldCapacity * 2;
        HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
        if (size == 0) {
            return newTable;
        }

        for (int j = 0; j < oldCapacity; j++) {
            /*
             * Rehash the bucket using the minimum number of field writes.
             * This is the most subtle and delicate code in the class.
             */
            HashMapEntry<K, V> e = oldTable[j];
            if (e == null) {
                continue;
            }
            int highBit = e.hash & oldCapacity;
            HashMapEntry<K, V> broken = null;
            newTable[j | highBit] = e;
            for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
                int nextHighBit = n.hash & oldCapacity;
                if (nextHighBit != highBit) {
                    if (broken == null)
                        newTable[j | nextHighBit] = n;
                    else
                        broken.next = n;
                    broken = e;
                    highBit = nextHighBit;
                }
            }
            if (broken != null)
                broken.next = null;
        }
        return newTable;
   }



哈希表有多种不同的实现方法

==============================================================

2. Get
获取的思想比较简单。不需要判断有没有重复的元素:
原理:
跟HashCode 获取元素在HashTable中的位置 index. 然后判断Key是不是相同,如果相同取出。 否则循环遍历链表。


    /**
     * Returns the value of the mapping with the specified key.
     *
     * @param key
     *            the key.
     * @return the value of the mapping with the specified key, or {@code null}
     *         if no mapping for the specified key is found.
     */
    public V get(Object key) {
        if (key == null) {
            HashMapEntry<K, V> e = entryForNullKey;
            return e == null ? null : e.value;
        }

        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
                e != null; e = e.next) {
            K eKey = e.key;
            // Key code in this line
            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
                return e.value;
            }
        }
        return null;
    }

==============================================================

3. 解决hash冲突的办法

  1. 开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
  2. 再哈希法
  3. 链地址法
  4. 建立一个公共溢出区
Java中hashmap的解决办法就是采用的链地址法。

==============================================================


See the UML 



总结:
HashMap是基于”拉链法“实现的散列表,一般用于单线程,键值都可以为空,支持Iterator(迭代器)遍历
Hashtable是基于”拉链法“实现的散列表,是线程安全的,可以用于多线程程序中。支持Iterator(迭代器)遍历和Enumeration(枚举器)两种遍历方式。
WeakHashMap也是基于”拉链法“实现的散列表,同时是弱键
TreeMap 是有序的散列表,通过红黑树来实现的,键值都不能为空。

==============================================================


写的非常的不错,因为是我的学长 哈哈




参考链接:

http://blog.csdn.net/speedme/article/details/22398395

http://blog.csdn.net/shimiso/article/details/10181801

http://blog.csdn.net/vking_wang/article/details/14166593

http://blog.csdn.net/qq924862077/article/details/48039643

http://liujiacai.net/blog/2015/09/04/java-treemap/




Sunday, September 13, 2015

JAVA中的反射机制

反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧!

           一,先看一下反射的概念:
              主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
             反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
             看概念很晕的,继续往下看。

      二,反射机制的作用:
              1,反编译:.class-->.java
              2,通过反射机制访问java对象的属性,方法,构造方法等;
             这样好像更容易理解一些,下边我们具体看怎么实现这些功能。

      三,在这里先看一下sun为我们提供了那些反射机制中的类:
java.lang.Class;                
java.lang.reflect.Constructor; java.lang.reflect.Field;        
java.lang.reflect.Method;
java.lang.reflect.Modifier;

            很多反射中的方法,属性等操作我们可以从这四个类中查询。还是哪句话要学着不断的查询API,那才是我们最好的老师。

         四,具体功能实现:
                1,反射机制获取类有三种方法,我们来获取Employee类型
  1. //第一种方式:  
  2. Classc1 = Class.forName("Employee");  
  3. //第二种方式:  
  4. //java中每个类型都有class 属性.  
  5. Classc2 = Employee.class;  
  6.    
  7. //第三种方式:  
  8. //java语言中任何一个java对象都有getClass 方法  
  9. Employeee = new Employee();  
  10. Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  


    2,创建对象:获取类以后我们来创建它的对象,利用newInstance
  1. Class c =Class.forName("Employee");  
  2.   
  3. //创建此Class 对象所表示的类的一个新实例  
  4. Objecto = c.newInstance(); //调用了Employee的无参数构造方法.  


    3,获取属性:分为所有的属性和指定的属性:
      a,先看获取所有的属性的写法:
  1. //获取整个类  
  2.             Class c = Class.forName("java.lang.Integer");  
  3.               //获取所有的属性?  
  4.             Field[] fs = c.getDeclaredFields();  
  5.        
  6.                    //定义可变长的字符串,用来存储属性  
  7.             StringBuffer sb = new StringBuffer();  
  8.             //通过追加的方法,将每个属性拼接到此字符串中  
  9.             //最外边的public定义  
  10.             sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
  11.             //里边的每一个属性  
  12.             for(Field field:fs){  
  13.                 sb.append("\t");//空格  
  14.                 sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等  
  15.                 sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字  
  16.                 sb.append(field.getName()+";\n");//属性的名字+回车  
  17.             }  
  18.       
  19.             sb.append("}");  
  20.       
  21.             System.out.println(sb);  

       b,获取特定的属性,对比着传统的方法来学习:

  1. public static void main(String[] args) throws Exception{  
  2.               
  3. <span style="white-space:pre">  </span>//以前的方式:  
  4.     /* 
  5.     User u = new User(); 
  6.     u.age = 12; //set 
  7.     System.out.println(u.age); //get 
  8.     */  
  9.               
  10.     //获取类  
  11.     Class c = Class.forName("User");  
  12.     //获取id属性  
  13.     Field idF = c.getDeclaredField("id");  
  14.     //实例化这个类赋给o  
  15.     Object o = c.newInstance();  
  16.     //打破封装  
  17.     idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。  
  18.     //给o对象的id属性赋值"110"  
  19.     idF.set(o, "110"); //set  
  20.     //get  
  21.     System.out.println(idF.get(o));  
  22. }  

 4,获取方法,和构造方法,不再详细描述,只来看一下关键字:
方法关键字
含义
getDeclaredMethods()
获取所有的方法
getReturnType()
获得方法的放回类型
getParameterTypes()
获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法


构造方法关键字
含义
getDeclaredConstructors()
获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法


父类和父接口
含义
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口
  
         这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

  五,反射加配置文件,使我们的程序更加灵活:
             在设计模式学习当中,学习抽象工厂的时候就用到了反射来更加方便的读取数据库链接字符串等,当时不是太理解,就照着抄了。看一下.NET中的反射+配置文件的使用:
             当时用的配置文件是app.config文件,内容是XML格式的,里边填写链接数据库的内容:
  1.       <configuration>  
  2. lt;appSettings>  
  3. <add     key=""  value=""/>  
  4. lt;/appSettings>  
  5.         </configuration>  

 反射的写法:   
  1. assembly.load("当前程序集的名称").CreateInstance("当前命名空间名称".要实例化的类名);  


          这样的好处是很容易的方便我们变换数据库,例如我们将系统的数据库从SQL Server升级到Oracle,那么我们写两份D层,在配置文件的内容改一下,或者加条件选择一下即可,带来了很大的方便。
            
         当然了,JAVA中其实也是一样,只不过这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配置文件的内容我们可以改,这样使我们的代码灵活了很多!

    综上为,JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。