Java

Java

CodeMix 3升级,对标Java版本Vscode,MyEclipse使用者不用换IDE多语言开发

下载|安装|配置|更新momo77 发表了文章 • 0 个评论 • 172 次浏览 • 2019-12-23 15:45 • 来自相关话题

可能很多国内Java开发者还没有使用过**[CodeMix](https://www.myeclipsecn.com/codemix/)**这个神奇的组件,本帖就再来介绍一下。
![请输入图片名称](https://www.evget.com/Content/ ... 76.png)
Codemix是基于Eclipse的插件,可以让你使用到如VS Code一样的Code OSS扩展社区,以及Webclipse 1.x特性。CodeMix可以安装在基于Eclipse的IDE上,从**[MyEclipse](https://www.myeclipsecn.com/)**到Spring工具套件,并且与PDT和PyDev等流行插件兼容。
![请输入图片名称](https://www.evget.com/Content/ ... 77.gif)
CodeMix最近的版本是于本月(2019年12月)11日发布的,版本号为CI 2019.12.11。此版本是CodeMix 3的一个小升级,更新了以下内容:
- **Eclipse 2019-12兼容性。**
CodeMix CI 2019.12.11与Eclipse的12月发行版兼容,您可以将Eclipse所有最新功能和修补程序与CodeMix一起使用。
- **macOS Catalina兼容性。**
默认情况下,macOS Catalina上对“zsh”shell的更改破坏了某些集成。CodeMix最新版将继续使用Bash来保持集成按预期运行。

[双旦钜惠,购MyEclipse、CodeMix折上折,消费满额享好礼>>>](https://www.evget.com/game/christmas/index)

对一个开发人员来讲,IDE的稳定性很重要。既然是插件,体积最好不要过大以免加载缓慢。
官方提供的CodeMix 3的安装环境建议还是挺简单的,个人认为任何一台开发电脑都完全没有问题:
- Eclipse 2019-06 through 4.6 (Neon)
- Eclipse Update Site or Discovery Site Available
- ~300MB 硬盘空间
- 0.5 GB – 2 GB free RAM (如果安装的扩展更多的化可能需要更多)
- Windows 32/64-bit, Linux 32/64-bit, Mac 64-bit
这里说到的Eclipse版本的问题,MyEclipse的使用者就需要[升级到最新版本(Myelcipse2019.12.5)](https://www.myeclipsecn.com/download/)。
## CodeMix 3的安装方式 ##
要从Eclipse Marketplace下载并安装CodeMix,请将上面的按钮拖到正在运行的Eclipse工作区中。此方法需要Marketplace客户端。
或者,你也可以通过更新站点直接从Eclipse安装: http://www.genuitec.com/updates/codemix/ci/ 。
也可以参考这篇**[CodeMix安装教程](https://www.evget.com/article/2018/10/31/28753.html)** 查看全部
可能很多国内Java开发者还没有使用过**[CodeMix](https://www.myeclipsecn.com/codemix/)**这个神奇的组件,本帖就再来介绍一下。
![请输入图片名称](https://www.evget.com/Content/ ... 76.png)
Codemix是基于Eclipse的插件,可以让你使用到如VS Code一样的Code OSS扩展社区,以及Webclipse 1.x特性。CodeMix可以安装在基于Eclipse的IDE上,从**[MyEclipse](https://www.myeclipsecn.com/)**到Spring工具套件,并且与PDT和PyDev等流行插件兼容。
![请输入图片名称](https://www.evget.com/Content/ ... 77.gif)
CodeMix最近的版本是于本月(2019年12月)11日发布的,版本号为CI 2019.12.11。此版本是CodeMix 3的一个小升级,更新了以下内容:
- **Eclipse 2019-12兼容性。**
CodeMix CI 2019.12.11与Eclipse的12月发行版兼容,您可以将Eclipse所有最新功能和修补程序与CodeMix一起使用。
- **macOS Catalina兼容性。**
默认情况下,macOS Catalina上对“zsh”shell的更改破坏了某些集成。CodeMix最新版将继续使用Bash来保持集成按预期运行。

[双旦钜惠,购MyEclipse、CodeMix折上折,消费满额享好礼>>>](https://www.evget.com/game/christmas/index)

对一个开发人员来讲,IDE的稳定性很重要。既然是插件,体积最好不要过大以免加载缓慢。
官方提供的CodeMix 3的安装环境建议还是挺简单的,个人认为任何一台开发电脑都完全没有问题:
- Eclipse 2019-06 through 4.6 (Neon)
- Eclipse Update Site or Discovery Site Available
- ~300MB 硬盘空间
- 0.5 GB – 2 GB free RAM (如果安装的扩展更多的化可能需要更多)
- Windows 32/64-bit, Linux 32/64-bit, Mac 64-bit
这里说到的Eclipse版本的问题,MyEclipse的使用者就需要[升级到最新版本(Myelcipse2019.12.5)](https://www.myeclipsecn.com/download/)。
## CodeMix 3的安装方式 ##
要从Eclipse Marketplace下载并安装CodeMix,请将上面的按钮拖到正在运行的Eclipse工作区中。此方法需要Marketplace客户端。
或者,你也可以通过更新站点直接从Eclipse安装: http://www.genuitec.com/updates/codemix/ci/
也可以参考这篇**[CodeMix安装教程](https://www.evget.com/article/2018/10/31/28753.html)**

MyEclipse数据库教程:使用Java项目查看JPA工作方式

Java EE开发momo77 发表了文章 • 0 个评论 • 231 次浏览 • 2019-11-27 16:57 • 来自相关话题

**建立一个项目**
一般情况,JPA Facet将被添加到Java或Web项目中。在本教程中,您将使用一个简单的Java项目来查看JPA的工作方式。
注意:您可以[下载本教程中开发的项目](https://www.evget.com/resource/detail-demo-14494),然后导入到您的工作区中。
1、单击下拉箭头![请输入图片名称](https://www.evget.com/Content/ ... 53.png),然后选择Java Project。
2、在“Project Name”字段中输入SampleJPAProject,选择默认选项,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 58.gif)
3、单击![请输入图片名称](https://www.evget.com/Content/ ... 46.png),选择MyEclipse Database Explorer打开透视图。
4、在数据库浏览器中,选择MyEclipse Derby连接,然后单击。
![请输入图片名称](https://www.evget.com/Content/ ... 54.gif)
**注意:**在建立数据库连接之前,无法添加JPA Facet,因为需要选择要使用的连接。
5、切换回MyEclipse Java Enterprise透视图,右键单击项目,然后选择**[MyEclipse](https://www.myeclipsecn.com/)** > Project Facets > Install JPA Facet。
6、在目标运行时下拉列表中选择MyEclipse通用Java运行时,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 51.png)
7、从平台下拉列表中选择一个平台,如果JPA实现类型默认为用户库,则选择与所选平台相对应的库。如果未列出任何库,可单击![请输入图片名称](https://www.evget.com/Content/ ... 10.png)下载适当的库。
![请输入图片名称](https://www.evget.com/Content/ ... 16.png)
8、在“Connection”字段中选择MyEclipse Derby,选中“Add driver library to build path”和“Override default schema”复选框,然后从“Schema”下拉列表中选择CLASSICCARS。单击完成。
![请输入图片名称](https://www.evget.com/Content/ ... 24.gif)
现在,项目中已添加了完全配置的JPA Facet,其中包括JPA配置信息/DB连接信息以及添加到项目构建路径中的所有必需的JDBC和JPA库。如果这是一个Web项目,在将项目部署到应用程序服务器上并在其中运行时,所有构建路径的附加内容都将准备好进行部署。
![请输入图片名称](https://www.evget.com/Content/ ... 70.gif)

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

**创建一个Java包**

在下一个步骤中,对数据库表中的数据进行反向工程,并为项目生成实体。在进行逆向工程之前,需要创建一个Java包,并在其中放置这些实体。
1、展开项目,右键单击src文件夹,然后选择New > Package。
![请输入图片名称](https://www.evget.com/Content/ ... 07.gif)
2、在“Name”字段中输入com.myeclipseide.jpa,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 64.gif)

**逆向工程数据库表**

现在已经建立了项目,可以将PRODUCTLINE表反向工程到项目中,并开始使用所生成的实体。
1、右键单击该项目,然后选择JPA Tools > Generate Entities & DAOs。
**注意:**您可以选择使用MyEclipse逆向工程工具或DALI实体生成器。选择,单击“确定”,然后完成向导。本教程使用MyEclipse逆向工程工具。
![请输入图片名称](https://www.evget.com/Content/ ... 96.png)
2、选择PRODUCTLINE表,单击添加,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 42.gif)
在“Java Package”字段中,单击“ Browse”,然后选择先前创建的com.myeclipseide.jpa程序包。选中以下复选框:
- Entity Bean Generation:让MyEclipse生成注释为用作JPA实体的普通Java类。
- Create abstract class;如果您希望自定义生成的类,而不必每次都覆盖更改,则MyEclipse可以生成基本抽象类以及您可以自定义和使用的具体子类。每次进行反向工程时,MyEclipse只会覆盖抽象基类,并在具体子类中保留更改。
- Update persistence.xml:与Hibernate类似,您可以在JPA配置文件中列出正在使用的所有JPA实体。
- Java Data Access Generation:让MyEclipse生成DAO实用程序类,让您可以立即从数据库中保存/查找/更新/删除实体。此代码包含了JPA实体管理器,使得使用实体和数据库变得非常容易。
- Generate Precise findBy Methods:让MyEclipse生成findByXXX方法,其中XXX与反转的实体上的每个属性有关。这样一来,可以使用任何属性作为查找实体的方法,轻松地从数据库访问实体。
- Generate Java Interfaces:选择此选项将创建带有相应DAO实现类的接口类。取消选择此选项仅生成DAO实现类,而没有用于定义接口的单独类。
![请输入图片名称](https://www.evget.com/Content/ ... 15.gif)
3、单击完成。查看通过展开com.myeclipseide.jpa包生成的MyEclipse资源。
![请输入图片名称](https://www.evget.com/Content/ ... 44.gif)
生成的实体描述如下:
- EntityManagerHelper:使用直接JPA时,开发人员需要使用EntityManager class。EntityManager通过提供用于访问管理器的静态方法以及易于调用的最常用操作,此生成的帮助程序类让使用EntityManager的过程变得更加容易。
- IProductline:定义相应DAO实现类的接口的类。
- Productline:此类是表示数据库表PRODUCTLINE的JPA实体(POJO)。该POJO包含PRODUCTLINE表的字段,并表示数据库中的一行。
- ProductlineDAO:此类包含EntityManagerHelper以便为我们提供易于使用的方法,专门用于在数据库中添加/查找/更新和删除产品。
注意:逆向工程完成后,您可以打开“Persistence”透视图,使用某些持久性和数据源工具来分析数据库和项目中的数据。

**编写应用程序**

由于MyEclipse生成了许多代码,所以您可以快速将精力放在“Business Logic”上,或更具体地说是“实际完成工作的代码”。在本部分中,您将编写一个具有main方法的Java类,该方法将Productline插入数据库,对其进行检索、更新并删除。使用此代码,您会发现在应用程序中使用JPA实体是多么容易!
**一、创建一个类**
1、右键单击com.myeclipseide.jpa软件包,然后选择New Class。
2、在“Name”字段中键入RunJPA,选中Public static void main复选框,然后单击“Finish”。
![请输入图片名称](https://www.evget.com/Content/ ... 76.gif)
在构建新类和main方法之后,需要编写代码来操作Productline实例。
**注意:**以下代码看起来很长而且很复杂,这是因为我们试图在一个代码块中显示四个不同的示例。如果您查看每个操作(保存、加载、更新、删除),就会发现它们都不由几行代码组成。
3、将以下代码添加到main方法中,然后按CTRL + S保存。

{{{
/* 1. Create a reference to our ID */
String productLineID = "Men's Shoes";

/* 2. Create a new Productline instance */
Productline newProductline = new Productline(
productLineID,
"Shoes for men.", "Men's Shoes", null);

/* 3. Create a DAO instance to use */
ProductlineDAO dao = new ProductlineDAO();

/* 4. Store our new product line in the DB */
EntityManagerHelper.beginTransaction();
dao.save(newProductline);
EntityManagerHelper.commit();

/* 5. Now retrieve the new product line,
using the ID we created */
Productline loadedProductline = dao.findById(productLineID);

/* 6. Print out the product line information */
System.out.println("*NEW* Product Line
[productLine="
+
loadedProductline.getProductline() + ",
textDescription="
+
loadedProductline.getTextdescription() + ", image="
+
loadedProductline.getImage() + "]");

/*
* 7. Now let's change same value on the product line, and save the
* change
*/
loadedProductline.setTextdescription("Product line for men's shoes.");
EntityManagerHelper.beginTransaction();
dao.save(loadedProductline);
EntityManagerHelper.commit();

/*
* 8. Now let's load the product line from the DB again, and make sure
* it text description changed
*/
Productline secondLoadedProductline =
dao.findById(productLineID);
System.out.println("*REVISED* Product Line ["
+ "productLine=" +
secondLoadedProductline.getProductline()
+ ", textDescription=" +
secondLoadedProductline.getTextdescription()
+ ", image=" +
secondLoadedProductline.getImage() + "]");

/* 9. Now let's delete the product line from the DB */
EntityManagerHelper.beginTransaction();
dao.delete(secondLoadedProductline);
EntityManagerHelper.commit();

/*
* 10. To confirm the deletion, try and load it again and make sure it
* fails
*/
Productline deletedProductline = dao.findById(productLineID);

/*
* We use a simple inlined IF clause to test for null and print
* SUCCESSFUL/FAILED
*/
System.out.println("Productline deletion: "
+ (deletedProductline ==
null ? "SUCCESSFUL" : "FAILED"));
}}}
上面的代码看起来很复杂,但它做了很多简单的事情。例如,如果您只对在数据库中存储新项目感兴趣,则只需要程序中第1-3步中的代码,这相当于(减去注释)三行代码。以下是每个编号部分的细分:
PRODUCTLINE表使用产品线的名称作为主键。为了使本教程更容易理解,我们在字符串中定义了产品线名称,并在代码中多次运用(创建和存储产品线,然后检索两次)。
这将创建由MyEclipse生成的Productline POJO的新实例,并将其插入数据库中。对于本教程而言,这些值并不重要,所以我们只使用示例信息。
这将创建要使用的DAO实例。数据库访问需要DAO(这也是由MyEclipse生成的)。
这让DAO将新的产品系列存储在数据库中。因为要向数据库中写入一些内容,所以将save调用包含在事务中。

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

为了确保使用第1步中定义的ID正确存储了产品系列,我们要求DAO获取产品系列,并将结果分配给一个全新的对象,以完全确保从数据库中加载了什么。(我们可以将值分配回newProductline,但是出于本教程的目的,我们必须清楚地知道对象来源,并且加载的实例之前在代码中不存在)。
这将从已加载的实体中打印出值,以确保它只是存储在数据库中的值。
这将更改刚刚加载的POJO的值,以显示更新记录的工作方式。然后,使用DAO将更改提交回数据库。同样的,此操作被包含在事务中,以确保安全地更改数据库。
与步骤5一样,使用在步骤1中定义的ID从数据库中重新加载记录,以确保更新操作有效。然后打印出POJO值,以确保新描述已保存到数据库中。
这显示了如何从数据库删除记录。同样的,由于这需要更改数据库,因此该代码被包含在事务中。
与第8步和第5步类似,为了证明删除有效,我们尝试使用给定的ID从数据库加载实体。因为我们已经删除了Productline,所以这个操作应该是失败的。从DAO获得结果后,将使用嵌入式IF子句打印一条语句,以确保结果为null。
**二、运行应用程序**
1、右键单击项目,然后选择Run As > Java Application。
2、选择RunJPA应用程序,然后单击“确定”。
![请输入图片名称](https://www.evget.com/Content/ ... 70.png)
输出显示在Console视图中。
![请输入图片名称](https://www.evget.com/Content/ ... 30.jpg)
红色文本是来自MyEclipse中生成的DAO和EntityHelper类的默认日志消息。黑色文本是代码中用于跟踪进度的System.out.println文本。如您所见,第6步中的第一个打印输出和第8步中的更新打印输出都按预期工作。并且查询没有返回Productline,证明删除也很成功。

**资源**
[Oracle JPA注释参考](https://www.oracle.com/technet ... 1.html)
[BEA JPQL参考](https://www.evget.com/resource ... -17577) 查看全部
**建立一个项目**
一般情况,JPA Facet将被添加到Java或Web项目中。在本教程中,您将使用一个简单的Java项目来查看JPA的工作方式。
注意:您可以[下载本教程中开发的项目](https://www.evget.com/resource/detail-demo-14494),然后导入到您的工作区中。
1、单击下拉箭头![请输入图片名称](https://www.evget.com/Content/ ... 53.png),然后选择Java Project。
2、在“Project Name”字段中输入SampleJPAProject,选择默认选项,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 58.gif)
3、单击![请输入图片名称](https://www.evget.com/Content/ ... 46.png),选择MyEclipse Database Explorer打开透视图。
4、在数据库浏览器中,选择MyEclipse Derby连接,然后单击。
![请输入图片名称](https://www.evget.com/Content/ ... 54.gif)
**注意:**在建立数据库连接之前,无法添加JPA Facet,因为需要选择要使用的连接。
5、切换回MyEclipse Java Enterprise透视图,右键单击项目,然后选择**[MyEclipse](https://www.myeclipsecn.com/)** > Project Facets > Install JPA Facet。
6、在目标运行时下拉列表中选择MyEclipse通用Java运行时,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 51.png)
7、从平台下拉列表中选择一个平台,如果JPA实现类型默认为用户库,则选择与所选平台相对应的库。如果未列出任何库,可单击![请输入图片名称](https://www.evget.com/Content/ ... 10.png)下载适当的库。
![请输入图片名称](https://www.evget.com/Content/ ... 16.png)
8、在“Connection”字段中选择MyEclipse Derby,选中“Add driver library to build path”和“Override default schema”复选框,然后从“Schema”下拉列表中选择CLASSICCARS。单击完成。
![请输入图片名称](https://www.evget.com/Content/ ... 24.gif)
现在,项目中已添加了完全配置的JPA Facet,其中包括JPA配置信息/DB连接信息以及添加到项目构建路径中的所有必需的JDBC和JPA库。如果这是一个Web项目,在将项目部署到应用程序服务器上并在其中运行时,所有构建路径的附加内容都将准备好进行部署。
![请输入图片名称](https://www.evget.com/Content/ ... 70.gif)

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

**创建一个Java包**

在下一个步骤中,对数据库表中的数据进行反向工程,并为项目生成实体。在进行逆向工程之前,需要创建一个Java包,并在其中放置这些实体。
1、展开项目,右键单击src文件夹,然后选择New > Package。
![请输入图片名称](https://www.evget.com/Content/ ... 07.gif)
2、在“Name”字段中输入com.myeclipseide.jpa,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 64.gif)

**逆向工程数据库表**

现在已经建立了项目,可以将PRODUCTLINE表反向工程到项目中,并开始使用所生成的实体。
1、右键单击该项目,然后选择JPA Tools > Generate Entities & DAOs。
**注意:**您可以选择使用MyEclipse逆向工程工具或DALI实体生成器。选择,单击“确定”,然后完成向导。本教程使用MyEclipse逆向工程工具。
![请输入图片名称](https://www.evget.com/Content/ ... 96.png)
2、选择PRODUCTLINE表,单击添加,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 42.gif)
在“Java Package”字段中,单击“ Browse”,然后选择先前创建的com.myeclipseide.jpa程序包。选中以下复选框:
- Entity Bean Generation:让MyEclipse生成注释为用作JPA实体的普通Java类。
- Create abstract class;如果您希望自定义生成的类,而不必每次都覆盖更改,则MyEclipse可以生成基本抽象类以及您可以自定义和使用的具体子类。每次进行反向工程时,MyEclipse只会覆盖抽象基类,并在具体子类中保留更改。
- Update persistence.xml:与Hibernate类似,您可以在JPA配置文件中列出正在使用的所有JPA实体。
- Java Data Access Generation:让MyEclipse生成DAO实用程序类,让您可以立即从数据库中保存/查找/更新/删除实体。此代码包含了JPA实体管理器,使得使用实体和数据库变得非常容易。
- Generate Precise findBy Methods:让MyEclipse生成findByXXX方法,其中XXX与反转的实体上的每个属性有关。这样一来,可以使用任何属性作为查找实体的方法,轻松地从数据库访问实体。
- Generate Java Interfaces:选择此选项将创建带有相应DAO实现类的接口类。取消选择此选项仅生成DAO实现类,而没有用于定义接口的单独类。
![请输入图片名称](https://www.evget.com/Content/ ... 15.gif)
3、单击完成。查看通过展开com.myeclipseide.jpa包生成的MyEclipse资源。
![请输入图片名称](https://www.evget.com/Content/ ... 44.gif)
生成的实体描述如下:
- EntityManagerHelper:使用直接JPA时,开发人员需要使用EntityManager class。EntityManager通过提供用于访问管理器的静态方法以及易于调用的最常用操作,此生成的帮助程序类让使用EntityManager的过程变得更加容易。
- IProductline:定义相应DAO实现类的接口的类。
- Productline:此类是表示数据库表PRODUCTLINE的JPA实体(POJO)。该POJO包含PRODUCTLINE表的字段,并表示数据库中的一行。
- ProductlineDAO:此类包含EntityManagerHelper以便为我们提供易于使用的方法,专门用于在数据库中添加/查找/更新和删除产品。
注意:逆向工程完成后,您可以打开“Persistence”透视图,使用某些持久性和数据源工具来分析数据库和项目中的数据。

**编写应用程序**

由于MyEclipse生成了许多代码,所以您可以快速将精力放在“Business Logic”上,或更具体地说是“实际完成工作的代码”。在本部分中,您将编写一个具有main方法的Java类,该方法将Productline插入数据库,对其进行检索、更新并删除。使用此代码,您会发现在应用程序中使用JPA实体是多么容易!
**一、创建一个类**
1、右键单击com.myeclipseide.jpa软件包,然后选择New Class。
2、在“Name”字段中键入RunJPA,选中Public static void main复选框,然后单击“Finish”。
![请输入图片名称](https://www.evget.com/Content/ ... 76.gif)
在构建新类和main方法之后,需要编写代码来操作Productline实例。
**注意:**以下代码看起来很长而且很复杂,这是因为我们试图在一个代码块中显示四个不同的示例。如果您查看每个操作(保存、加载、更新、删除),就会发现它们都不由几行代码组成。
3、将以下代码添加到main方法中,然后按CTRL + S保存。

{{{
/* 1. Create a reference to our ID */
String productLineID = "Men's Shoes";

/* 2. Create a new Productline instance */
Productline newProductline = new Productline(
productLineID,
"Shoes for men.", "Men's Shoes", null);

/* 3. Create a DAO instance to use */
ProductlineDAO dao = new ProductlineDAO();

/* 4. Store our new product line in the DB */
EntityManagerHelper.beginTransaction();
dao.save(newProductline);
EntityManagerHelper.commit();

/* 5. Now retrieve the new product line,
using the ID we created */
Productline loadedProductline = dao.findById(productLineID);

/* 6. Print out the product line information */
System.out.println("*NEW* Product Line
[productLine="
+
loadedProductline.getProductline() + ",
textDescription="
+
loadedProductline.getTextdescription() + ", image="
+
loadedProductline.getImage() + "]");

/*
* 7. Now let's change same value on the product line, and save the
* change
*/
loadedProductline.setTextdescription("Product line for men's shoes.");
EntityManagerHelper.beginTransaction();
dao.save(loadedProductline);
EntityManagerHelper.commit();

/*
* 8. Now let's load the product line from the DB again, and make sure
* it text description changed
*/
Productline secondLoadedProductline =
dao.findById(productLineID);
System.out.println("*REVISED* Product Line ["
+ "productLine=" +
secondLoadedProductline.getProductline()
+ ", textDescription=" +
secondLoadedProductline.getTextdescription()
+ ", image=" +
secondLoadedProductline.getImage() + "]");

/* 9. Now let's delete the product line from the DB */
EntityManagerHelper.beginTransaction();
dao.delete(secondLoadedProductline);
EntityManagerHelper.commit();

/*
* 10. To confirm the deletion, try and load it again and make sure it
* fails
*/
Productline deletedProductline = dao.findById(productLineID);

/*
* We use a simple inlined IF clause to test for null and print
* SUCCESSFUL/FAILED
*/
System.out.println("Productline deletion: "
+ (deletedProductline ==
null ? "SUCCESSFUL" : "FAILED"));
}}}
上面的代码看起来很复杂,但它做了很多简单的事情。例如,如果您只对在数据库中存储新项目感兴趣,则只需要程序中第1-3步中的代码,这相当于(减去注释)三行代码。以下是每个编号部分的细分:
PRODUCTLINE表使用产品线的名称作为主键。为了使本教程更容易理解,我们在字符串中定义了产品线名称,并在代码中多次运用(创建和存储产品线,然后检索两次)。
这将创建由MyEclipse生成的Productline POJO的新实例,并将其插入数据库中。对于本教程而言,这些值并不重要,所以我们只使用示例信息。
这将创建要使用的DAO实例。数据库访问需要DAO(这也是由MyEclipse生成的)。
这让DAO将新的产品系列存储在数据库中。因为要向数据库中写入一些内容,所以将save调用包含在事务中。

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

为了确保使用第1步中定义的ID正确存储了产品系列,我们要求DAO获取产品系列,并将结果分配给一个全新的对象,以完全确保从数据库中加载了什么。(我们可以将值分配回newProductline,但是出于本教程的目的,我们必须清楚地知道对象来源,并且加载的实例之前在代码中不存在)。
这将从已加载的实体中打印出值,以确保它只是存储在数据库中的值。
这将更改刚刚加载的POJO的值,以显示更新记录的工作方式。然后,使用DAO将更改提交回数据库。同样的,此操作被包含在事务中,以确保安全地更改数据库。
与步骤5一样,使用在步骤1中定义的ID从数据库中重新加载记录,以确保更新操作有效。然后打印出POJO值,以确保新描述已保存到数据库中。
这显示了如何从数据库删除记录。同样的,由于这需要更改数据库,因此该代码被包含在事务中。
与第8步和第5步类似,为了证明删除有效,我们尝试使用给定的ID从数据库加载实体。因为我们已经删除了Productline,所以这个操作应该是失败的。从DAO获得结果后,将使用嵌入式IF子句打印一条语句,以确保结果为null。
**二、运行应用程序**
1、右键单击项目,然后选择Run As > Java Application。
2、选择RunJPA应用程序,然后单击“确定”。
![请输入图片名称](https://www.evget.com/Content/ ... 70.png)
输出显示在Console视图中。
![请输入图片名称](https://www.evget.com/Content/ ... 30.jpg)
红色文本是来自MyEclipse中生成的DAO和EntityHelper类的默认日志消息。黑色文本是代码中用于跟踪进度的System.out.println文本。如您所见,第6步中的第一个打印输出和第8步中的更新打印输出都按预期工作。并且查询没有返回Productline,证明删除也很成功。

**资源**
[Oracle JPA注释参考](https://www.oracle.com/technet ... 1.html)
[BEA JPQL参考](https://www.evget.com/resource ... -17577)

Java全栈开发工程师力荐工具MyEclipse&CodeMix年终让利|限时折上折

MyEclipse IDE公告momo77 发表了文章 • 0 个评论 • 125 次浏览 • 2019-11-20 10:11 • 来自相关话题

作为Java开发人员,你是否找到了喜欢的开发工具?
本文介绍的这两款市面最流行、价格最实惠、功能最强大的Java开发神器,一定能让你用一次就爱不释手!

**[MyEclipse——企业级Java EE开发工具](https://www.myeclipsecn.com/)**

提起MyEclipse,从事Java工作或学习的朋友们应该很熟悉,它是Eclispse的进一步扩展,是企业级Java EE开发工具。它包括了完备的编码、调试、测试和发布功能,同时也支持Java Servlet、AJAX、JSP、JSF、Struts、SpringHibernate、EJB3、JDBC数据库链接工具等多项功能,主要用于Java、Java EE及Web开发。
由此可见,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持相当不错。
![请输入图片名称](https://www.evget.com/Content/ ... 61.png)

**[免费试用30天](https://www.myeclipsecn.com/download/)** **[优惠购买正版授权](https://www.evget.com/mall/detail/3016)**

其实网络上对于Java的编译器有着非常大的争端。有的人说IDEA好,也有说MyEclipse强大的。但是在小编看来,工具嘛,个人使用顺手就好啦,没必要硬扯出个输赢。
经常与MyEclipse一起出现的还有CodeMix。

**[CodeMix——代码自动补全插件](https://www.myeclipsecn.com/codemix/)**

CodeMix是Eclipse IDE代码自动补全插件,具有智能代码完成、键盘电源与命令、调试等功能,可以执行从打开文件到运行构建的所有操作,根据语言语义和代码分析,在你输入代码的时候显示内容辅助建议、进行代码自动补全,还能添加断点、找出代码中的错误。由此可见,可能使用CodeMix的人永远都不能理解加班狗的痛苦。
最让Java开发人员喜欢的是,CodeMix与基于Eclipse的IDE和工具兼容(比如MyEclipse),即使是初次使用CodeMixd的人也能在熟悉的环境中快速工作。
重点是,CodeMix解锁了VS Code和Code OSS附加扩展的各种技术。所以,如果你羡慕VS Code的超快速度,一定要带走CodeMix,因为它能增强你的工作流程和开发速度!

**[优惠购买正版授权](https://www.evget.com/mall/detail/4078)**

或许你现在已经心动了,又或许你早就盯上了上述两款工具,但还在观摩等待更实惠的价格。慧都网不仅知你所需,还要给你想要:
[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)
注意,慧都商城中MyEclipse的商业授权包括标准版、专业版、Spring版、Blue版和Bling版:
- 标准版可以满足Jave EE入门开发的需求;
- 专业版除可以满足Jave EE入门开发的需求外,还拥有能应付所有应用程序开发的灵活工具集;
- 而Blue版和Spring版则是在专业版基础上分别增加了完整支持WebSphere和Spring开发的工具集;
- Bling版是Blue版和Spring版的并集。
所以,在购买时一定要根据自己的实际需求选购合适的版本哦!(土豪除外~)
提示:对于Jave EE入门开发的工具集来说,五个版本的MyEclipse都可以满足需求;如果你需要支持WebSphere的完整工具集,可以选择Blue版或Bling版。若您有其他疑问,欢迎**[【联系客服】](https://chat8.live800.com/live ... Bs%3D1)**了解~

**[MyEclipse&CodeMix资源集锦](https://www.evget.com/topic/22)**
视频资源、移动开发/Web开发/数据库教程、各版本更新要点,应有尽有。 查看全部
作为Java开发人员,你是否找到了喜欢的开发工具?
本文介绍的这两款市面最流行、价格最实惠、功能最强大的Java开发神器,一定能让你用一次就爱不释手!

**[MyEclipse——企业级Java EE开发工具](https://www.myeclipsecn.com/)**

提起MyEclipse,从事Java工作或学习的朋友们应该很熟悉,它是Eclispse的进一步扩展,是企业级Java EE开发工具。它包括了完备的编码、调试、测试和发布功能,同时也支持Java Servlet、AJAX、JSP、JSF、Struts、SpringHibernate、EJB3、JDBC数据库链接工具等多项功能,主要用于Java、Java EE及Web开发。
由此可见,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持相当不错。
![请输入图片名称](https://www.evget.com/Content/ ... 61.png)

**[免费试用30天](https://www.myeclipsecn.com/download/)** **[优惠购买正版授权](https://www.evget.com/mall/detail/3016)**

其实网络上对于Java的编译器有着非常大的争端。有的人说IDEA好,也有说MyEclipse强大的。但是在小编看来,工具嘛,个人使用顺手就好啦,没必要硬扯出个输赢。
经常与MyEclipse一起出现的还有CodeMix。

**[CodeMix——代码自动补全插件](https://www.myeclipsecn.com/codemix/)**

CodeMix是Eclipse IDE代码自动补全插件,具有智能代码完成、键盘电源与命令、调试等功能,可以执行从打开文件到运行构建的所有操作,根据语言语义和代码分析,在你输入代码的时候显示内容辅助建议、进行代码自动补全,还能添加断点、找出代码中的错误。由此可见,可能使用CodeMix的人永远都不能理解加班狗的痛苦。
最让Java开发人员喜欢的是,CodeMix与基于Eclipse的IDE和工具兼容(比如MyEclipse),即使是初次使用CodeMixd的人也能在熟悉的环境中快速工作。
重点是,CodeMix解锁了VS Code和Code OSS附加扩展的各种技术。所以,如果你羡慕VS Code的超快速度,一定要带走CodeMix,因为它能增强你的工作流程和开发速度!

**[优惠购买正版授权](https://www.evget.com/mall/detail/4078)**

或许你现在已经心动了,又或许你早就盯上了上述两款工具,但还在观摩等待更实惠的价格。慧都网不仅知你所需,还要给你想要:
[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)
注意,慧都商城中MyEclipse的商业授权包括标准版、专业版、Spring版、Blue版和Bling版:
- 标准版可以满足Jave EE入门开发的需求;
- 专业版除可以满足Jave EE入门开发的需求外,还拥有能应付所有应用程序开发的灵活工具集;
- 而Blue版和Spring版则是在专业版基础上分别增加了完整支持WebSphere和Spring开发的工具集;
- Bling版是Blue版和Spring版的并集。
所以,在购买时一定要根据自己的实际需求选购合适的版本哦!(土豪除外~)
提示:对于Jave EE入门开发的工具集来说,五个版本的MyEclipse都可以满足需求;如果你需要支持WebSphere的完整工具集,可以选择Blue版或Bling版。若您有其他疑问,欢迎**[【联系客服】](https://chat8.live800.com/live ... Bs%3D1)**了解~

**[MyEclipse&CodeMix资源集锦](https://www.evget.com/topic/22)**
视频资源、移动开发/Web开发/数据库教程、各版本更新要点,应有尽有。

【重要通知】Javonet跨语言整合公开课 今日开讲啦!(内附听课教程)

综合讨论区besy 发表了文章 • 0 个评论 • 88 次浏览 • 2018-07-31 09:40 • 来自相关话题

慧都学院Javonet跨语言整合公开课今日下午2点30准点开讲,本文内附听课教程,开课前可免费下载Javonet产品,购买还可享折上折。
![请输入图片名称](https://image.evget.com//Conte ... 53.jpg)

## [Javonet跨语言整合公开课](http://www.evgetedu.com/open/detail/5148) ##

**开课时间:2018/7/31 下午2:30 准时开讲!**
## 【课程亮点】 ##

- 厂商CTO亲自授课,用一节课解决您跨语言之间的壁垒;
- 概况跨语言整合( C++/COM、. NET 和 Java 之间跨语言整合)技术介绍以及如何在安全的环境下加速您的开发项目;
- 从一般的整合概率出发,到具体的解决方案和它的优点,并优化与IT项目以及Javonet使用的最佳场景。
## 【适合人群】 ##

系统架构师;.NET开发人员;Java开发者;系统整合人员;团队领导、IT经理

**[听课教程](https://www.evget.com/article/2018/7/30/28241.html)** 查看全部
慧都学院Javonet跨语言整合公开课今日下午2点30准点开讲,本文内附听课教程,开课前可免费下载Javonet产品,购买还可享折上折。
![请输入图片名称](https://image.evget.com//Conte ... 53.jpg)

## [Javonet跨语言整合公开课](http://www.evgetedu.com/open/detail/5148) ##

**开课时间:2018/7/31 下午2:30 准时开讲!**
## 【课程亮点】 ##

- 厂商CTO亲自授课,用一节课解决您跨语言之间的壁垒;
- 概况跨语言整合( C++/COM、. NET 和 Java 之间跨语言整合)技术介绍以及如何在安全的环境下加速您的开发项目;
- 从一般的整合概率出发,到具体的解决方案和它的优点,并优化与IT项目以及Javonet使用的最佳场景。
## 【适合人群】 ##

系统架构师;.NET开发人员;Java开发者;系统整合人员;团队领导、IT经理

**[听课教程](https://www.evget.com/article/2018/7/30/28241.html)**

求大神帮忙看看问题出在哪里?编程小白要愁哭了。。。

Java EE开发qiahuangzhang 回复了问题 • 5 人关注 • 4 个回复 • 177 次浏览 • 2017-06-11 22:53 • 来自相关话题

问大家个问题,Java工程bin目录试图窗口不可见

回复

综合讨论区匿名用户 发起了问题 • 1 人关注 • 0 个回复 • 11 次浏览 • 2016-10-18 21:50 • 来自相关话题

常用 Java API 汇总

回复

综合讨论区besy 发起了问题 • 1 人关注 • 0 个回复 • 112 次浏览 • 2016-03-03 09:50 • 来自相关话题

【附示例】Java 程 序 员 必 知 的 8 大 排 序

综合讨论区besy 发表了文章 • 0 个评论 • 231 次浏览 • 2015-10-15 11:26 • 来自相关话题

8种排序之间的关系:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 68.png)

## 1、直接插入排序 ##

(1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排

好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数

也是排好顺序的。如此反复循环,直到全部排好顺序。

(2)实例

![请输入图片名称](http://my.csdn.net/uploads/201 ... 87.png)

(3)用java实现

{{{
package com.njue;

public class insertSort {
public insertSort(){
inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=1;i<a.length;i++){
int j=i-1;
temp=a[i];
for(;j>=0&&temp<a[j];j--){
a[j+1]=a[j]; //将大于temp的值整体后移一个单位
}
a[j+1]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 2、希尔排序(最小增量排序) ##

(1)基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 15.png)

(3)用java实现

{{{
public class shellSort {
public shellSort(){
int a[]={1,54,6,3,78,34,12,45,56,100};
double d1=a.length;
int temp=0;
while(true){
d1= Math.ceil(d1/2);
int d=(int) d1;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j=i-d;
temp=a[i];
for(;j>=0&&temp<a[j];j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
if(d==1)
break;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 3.简单选择排序 ##

(1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 19.png)

(3)用java实现

{{{
public class selectSort {
public selectSort(){
int a[]={1,54,6,3,78,34,12,45};
int position=0;
for(int i=0;i<a.length;i++){

int j=i+1;
position=i;
int temp=a[i];
for(;j<a.length;j++){
if(a[j]<temp){
temp=a[j];
position=j;
}
}
a[position]=a[i];
a[i]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 4、 堆排序 ##

(1)基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

(2)实例:

初始序列:46,79,56,38,40,84

建堆:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 48.png)

交换,从堆中踢出最大数

![请输入图片名称](http://my.csdn.net/uploads/201 ... 47.png)

![请输入图片名称](http://my.csdn.net/uploads/201 ... 88.png)

依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。

(3)用java实现

{{{
import java.util.Arrays;

public class HeapSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public HeapSort(){
heapSort(a);
}
public void heapSort(int[] a){
System.out.println("开始排序");
int arrayLength=a.length;
//循环建堆
for(int i=0;i<arrayLength-1;i++){
//建堆

buildMaxHeap(a,arrayLength-1-i);
//交换堆顶和最后一个元素
swap(a,0,arrayLength-1-i);
System.out.println(Arrays.toString(a));
}
}

private void swap(int[] data, int i, int j) {
// TODO Auto-generated method stub
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
//对data数组从0到lastIndex建大顶堆
private void buildMaxHeap(int[] data, int lastIndex) {
// TODO Auto-generated method stub
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i=(lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k=biggerIndex;
}else{
break;
}
}<p align="left">&nbsp;<span> </span>}</p><p align="left">&nbsp;&nbsp;&nbsp; }</p><p align="left">&nbsp;<span style="background-color: white; ">}</span></p>

}}}

## 5.冒泡排序 ##

(1)基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 67.png)

(3)用java实现

{{{
public class bubbleSort {
public bubbleSort(){
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}

}}}

## 6.快速排序 ##

(1)基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 95.png)

(3)用java实现

{{{
public class quickSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public quickSort(){
quick(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; //数组的第一个作为中轴
while (low < high) {
while (low < high && list[high] >= tmp) {

high--;
}
list[low] = list[high]; //比中轴小的记录移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; //比中轴大的记录移到高端
}
list[low] = tmp; //中轴记录到尾
return low; //返回中轴的位置
}
public void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); //将list数组进行一分为二
_quickSort(list, low, middle - 1); //对低字表进行递归排序
_quickSort(list, middle + 1, high); //对高字表进行递归排序
}
}
public void quick(int[] a2) {
if (a2.length > 0) { //查看数组是否为空
_quickSort(a2, 0, a2.length - 1);
}
}
}
}}}

## 7、归并排序 ##

(1)基本排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 91.png)

(3)用java实现

{{{
import java.util.Arrays;

public class mergingSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public mergingSort(){
sort(a,0,a.length-1);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] data, int left, int right) {
// TODO Auto-generated method stub
if(left<right){
//找出中间索引
int center=(left+right)/2;
//对左边数组进行递归
sort(data,left,center);
//对右边数组进行递归
sort(data,center+1,right);
//合并
merge(data,left,center,right);

}
}
public void merge(int[] data, int left, int center, int right) {
// TODO Auto-generated method stub
int [] tmpArr=new int[data.length];
int mid=center+1;
//third记录中间数组的索引
int third=left;
int tmp=left;
while(left<=center&&mid<=right){

//从两个数组中取出最小的放入中间数组
if(data[left]<=data[mid]){
tmpArr[third++]=data[left++];
}else{
tmpArr[third++]=data[mid++];
}
}
//剩余部分依次放入中间数组
while(mid<=right){
tmpArr[third++]=data[mid++];
}
while(left<=center){
tmpArr[third++]=data[left++];
}
//将中间数组中的内容复制回原数组
while(tmp<=right){
data[tmp]=tmpArr[tmp++];
}
System.out.println(Arrays.toString(data));
}

}
}}}

## 8、基数排序 ##

(1)基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 46.png)

(3)用java实现

{{{
import java.util.ArrayList;
import java.util.List;

public class radixSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,101,56,17,18,23,34,15,35,25,53,51};
public radixSort(){
sort(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] array){

//首先确定排序的趟数;
int max=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max){
max=array[i];
}
}

int time=0;
//判断位数;
while(max>0){
max/=10;
time++;
}

//建立10个队列;
List<ArrayList> queue=new ArrayList<ArrayList>();
for(int i=0;i<10;i++){
ArrayList<Integer> queue1=new ArrayList<Integer>();
queue.add(queue1);
}

//进行time次分配和收集;
for(int i=0;i<time;i++){

//分配数组元素;
for(int j=0;j<array.length;j++){
//得到数字的第time+1位数;
int x=array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
ArrayList<Integer> queue2=queue.get(x);
queue2.add(array[j]);
queue.set(x, queue2);
}
int count=0;//元素计数器;
//收集队列元素;
for(int k=0;k<10;k++){
while(queue.get(k).size()>0){
ArrayList<Integer> queue3=queue.get(k);
array[count]=queue3.get(0);
queue3.remove(0);
count++;
}
}
}
}

}
}}}

原文出处:http://blog.csdn.net/without08 ... 97916 查看全部
8种排序之间的关系:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 68.png)

## 1、直接插入排序 ##

(1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排

好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数

也是排好顺序的。如此反复循环,直到全部排好顺序。

(2)实例

![请输入图片名称](http://my.csdn.net/uploads/201 ... 87.png)

(3)用java实现

{{{
package com.njue;

public class insertSort {
public insertSort(){
inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=1;i<a.length;i++){
int j=i-1;
temp=a[i];
for(;j>=0&&temp<a[j];j--){
a[j+1]=a[j]; //将大于temp的值整体后移一个单位
}
a[j+1]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 2、希尔排序(最小增量排序) ##

(1)基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 15.png)

(3)用java实现

{{{
public class shellSort {
public shellSort(){
int a[]={1,54,6,3,78,34,12,45,56,100};
double d1=a.length;
int temp=0;
while(true){
d1= Math.ceil(d1/2);
int d=(int) d1;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j=i-d;
temp=a[i];
for(;j>=0&&temp<a[j];j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
if(d==1)
break;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 3.简单选择排序 ##

(1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 19.png)

(3)用java实现

{{{
public class selectSort {
public selectSort(){
int a[]={1,54,6,3,78,34,12,45};
int position=0;
for(int i=0;i<a.length;i++){

int j=i+1;
position=i;
int temp=a[i];
for(;j<a.length;j++){
if(a[j]<temp){
temp=a[j];
position=j;
}
}
a[position]=a[i];
a[i]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 4、 堆排序 ##

(1)基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

(2)实例:

初始序列:46,79,56,38,40,84

建堆:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 48.png)

交换,从堆中踢出最大数

![请输入图片名称](http://my.csdn.net/uploads/201 ... 47.png)

![请输入图片名称](http://my.csdn.net/uploads/201 ... 88.png)

依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。

(3)用java实现

{{{
import java.util.Arrays;

public class HeapSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public HeapSort(){
heapSort(a);
}
public void heapSort(int[] a){
System.out.println("开始排序");
int arrayLength=a.length;
//循环建堆
for(int i=0;i<arrayLength-1;i++){
//建堆

buildMaxHeap(a,arrayLength-1-i);
//交换堆顶和最后一个元素
swap(a,0,arrayLength-1-i);
System.out.println(Arrays.toString(a));
}
}

private void swap(int[] data, int i, int j) {
// TODO Auto-generated method stub
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
//对data数组从0到lastIndex建大顶堆
private void buildMaxHeap(int[] data, int lastIndex) {
// TODO Auto-generated method stub
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i=(lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k=biggerIndex;
}else{
break;
}
}<p align="left">&nbsp;<span> </span>}</p><p align="left">&nbsp;&nbsp;&nbsp; }</p><p align="left">&nbsp;<span style="background-color: white; ">}</span></p>

}}}

## 5.冒泡排序 ##

(1)基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 67.png)

(3)用java实现

{{{
public class bubbleSort {
public bubbleSort(){
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}

}}}

## 6.快速排序 ##

(1)基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 95.png)

(3)用java实现

{{{
public class quickSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public quickSort(){
quick(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; //数组的第一个作为中轴
while (low < high) {
while (low < high && list[high] >= tmp) {

high--;
}
list[low] = list[high]; //比中轴小的记录移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; //比中轴大的记录移到高端
}
list[low] = tmp; //中轴记录到尾
return low; //返回中轴的位置
}
public void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); //将list数组进行一分为二
_quickSort(list, low, middle - 1); //对低字表进行递归排序
_quickSort(list, middle + 1, high); //对高字表进行递归排序
}
}
public void quick(int[] a2) {
if (a2.length > 0) { //查看数组是否为空
_quickSort(a2, 0, a2.length - 1);
}
}
}
}}}

## 7、归并排序 ##

(1)基本排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 91.png)

(3)用java实现

{{{
import java.util.Arrays;

public class mergingSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public mergingSort(){
sort(a,0,a.length-1);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] data, int left, int right) {
// TODO Auto-generated method stub
if(left<right){
//找出中间索引
int center=(left+right)/2;
//对左边数组进行递归
sort(data,left,center);
//对右边数组进行递归
sort(data,center+1,right);
//合并
merge(data,left,center,right);

}
}
public void merge(int[] data, int left, int center, int right) {
// TODO Auto-generated method stub
int [] tmpArr=new int[data.length];
int mid=center+1;
//third记录中间数组的索引
int third=left;
int tmp=left;
while(left<=center&&mid<=right){

//从两个数组中取出最小的放入中间数组
if(data[left]<=data[mid]){
tmpArr[third++]=data[left++];
}else{
tmpArr[third++]=data[mid++];
}
}
//剩余部分依次放入中间数组
while(mid<=right){
tmpArr[third++]=data[mid++];
}
while(left<=center){
tmpArr[third++]=data[left++];
}
//将中间数组中的内容复制回原数组
while(tmp<=right){
data[tmp]=tmpArr[tmp++];
}
System.out.println(Arrays.toString(data));
}

}
}}}

## 8、基数排序 ##

(1)基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 46.png)

(3)用java实现

{{{
import java.util.ArrayList;
import java.util.List;

public class radixSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,101,56,17,18,23,34,15,35,25,53,51};
public radixSort(){
sort(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] array){

//首先确定排序的趟数;
int max=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max){
max=array[i];
}
}

int time=0;
//判断位数;
while(max>0){
max/=10;
time++;
}

//建立10个队列;
List<ArrayList> queue=new ArrayList<ArrayList>();
for(int i=0;i<10;i++){
ArrayList<Integer> queue1=new ArrayList<Integer>();
queue.add(queue1);
}

//进行time次分配和收集;
for(int i=0;i<time;i++){

//分配数组元素;
for(int j=0;j<array.length;j++){
//得到数字的第time+1位数;
int x=array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
ArrayList<Integer> queue2=queue.get(x);
queue2.add(array[j]);
queue.set(x, queue2);
}
int count=0;//元素计数器;
//收集队列元素;
for(int k=0;k<10;k++){
while(queue.get(k).size()>0){
ArrayList<Integer> queue3=queue.get(k);
array[count]=queue3.get(0);
queue3.remove(0);
count++;
}
}
}
}

}
}}}

原文出处:http://blog.csdn.net/without08 ... 97916

【干货分享】Java那些不为人知的特殊方法

综合讨论区besy 发表了文章 • 0 个评论 • 128 次浏览 • 2015-10-14 16:01 • 来自相关话题

如果你用过反射并且执行过getDeclaredMethods方法的话,你可能会感到很吃惊。你会发现出现了很多源代码里没有的方法。如果你看一下这些方法的修饰符的话,可能会发现里面有些方法是volatile的。顺便说一句,如果在Java面试里问到“什么是volatile方法?”,你可能会吓出一身冷汗。正确的答案是没有volatile方法。但同时,getDeclaredMethods()或者getMethods()返回的这些方法,Modifier.isVolatile(method.getModifiers())的结果却是true。

immutator的一些用户遇到过这样的问题。他们发现,使用immutator(这个项目探索了Java的一些不为人知的细节)生成的Java代码使用volatile了作为方法的关键字,而这样的代码没法通过编译。结果就是这根本没法用。

这是怎么回事?syntethic和bridge方法又是什么?
可见性

当你创建一个嵌套类的时候,它的私有变量和方法对上层的类是可见的。这个在不可变嵌套式Builder模式中用到了。这是Java语言规范里已经定义好的一个行为。

{{{package synthetic;

public class SyntheticMethodTest1 {
private A aObj = new A();

public class A {
private int i;
}

private class B {
private int i = aObj.i;
}

public static void main(String[] args) {
SyntheticMethodTest1 me = new SyntheticMethodTest1();
me.aObj.i = 1;
B bObj = me.new B();
System.out.println(bObj.i);
}
}}}}

JVM是如何处理这个的?它可不知道什么是内部类或者嵌套类的。JVM对所有的类都一视同仁,它都认为是顶级类。所有类都会被编译成顶级类,而那些内部类编译完后会生成...$... class的类文件。

{{{$ ls -Fart
../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java
SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java}}}

如果你创建一个内部类的话,它会被彻底编译成一个顶级类。

那这些私有变量又是如何被外部类访问的呢?如果它们是个顶级类的私有变量(它们的确也是),那为什么别的类还能直接访问这些变量?

javac是这样解决这个问题的,对于任何private的字段,方法或者构造函数,如果它们也被其它顶层类所使用,就会生成一个synthetic方法。这些synthetic方法是用来访问最初的私有变量/方法/构造函数的。这些方法的生成也很智能:只有确实被外部类用到了,才会生成这样的方法。

{{{package synthetic;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class SyntheticMethodTest2 {

public static class A {
private A(){}
private int x;
private void x(){};
}

public static void main(String[] args) {
A a = new A();
a.x = 2;
a.x();
System.out.println(a.x);
for (Method m : A.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getName());
}
System.out.println("--------------------------");
for (Method m : A.class.getMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
System.out.println("--------------------------");
for( Constructor<?> c : A.class.getDeclaredConstructors() ){
System.out.println(String.format("X", c.getModifiers()) + " " + c.getName());
}
}
} }}}

这些生成的方法的名字取决于具体的实现,最后叫什么也不好说。我只能说在我运行的这个平台上,上述程序的输出是这样的:

{{{2
00001008 access$1
00001008 access$2
00001008 access$3
00000002 x
--------------------------
00000111 void wait
00000011 void wait
00000011 void wait
00000001 boolean equals
00000001 String toString
00000101 int hashCode
00000111 Class getClass
00000111 void notify
00000111 void notifyAll
--------------------------
00000002 synthetic.SyntheticMethodTest2$A
00001000 synthetic.SyntheticMethodTest2$A }}}

在上面这个程序中,我们给变量x赋值,然后又调用了一个同名的方法。这会触发编译器生成对应的synthetic方法。你会看到它生成了三个方法,应该是x变量的setter和getter方法,以及x()方法对应的一个synthetic方法。这些方法并不存在于getMethods方法里返回的列表中,因为它们是synthetic方法,是不能直接被调用的。从这点来看,它们和私有方法差不多。

看一下java.lang.reflect.Modifier里面定义的常量,可以明白这些十六进制的数字代表的是什么:

{{{00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC }}}

列表中有两个是构造方法。还有一个私有方法以及一个synthetic方法。存在这个私有方法是因为我们确实定义了它。而synthetic方法的出现是因为我们从外部类调用了它内部的私有成员。到目前为止,还没有出现过bridge方法。
泛型和继承

到目前为止,看起来还不错。不过我们还没有看到”volatile”方法。

看一下java.lang.reflect.Modifier的源码你会发现0x00000040这个常量被定义了两次。一次是定义成VOLATILE,还有一次是BRIDGE(后者是包内部私有的,并不对外开放)。

想出现volatile方法的话,写个简单的程序就行了:

{{{package synthetic;

import java.lang.reflect.Method;
import java.util.LinkedList;

public class SyntheticMethodTest3 {

public static class MyLink extends LinkedList<String> {
@Override
public String get(int i) {
return "";
}
}

public static void main(String[] args) {

for (Method m : MyLink.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
}
}}}}

这个链表有一个返回String的get(int)方法。先别讨论代码整不整洁的问题了。这只是段示例代码而已。整洁的代码当然也会出现同样的问题,不过越复杂的代码越难定位问题罢了。

输出的结果是这样的:

{{{00000001 String get
00001041 Object get }}}

这里有两个get方法。一个是代码里的那个,另外一个是synthetic和bridge方法。用javap反编译后会是这样的:

{{{public java.lang.String get(int);
Code:
Stack=1, Locals=2, Args_size=2
0: ldc #2; //String
2: areturn
LineNumberTable:
line 12: 0

public java.lang.Object get(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokevirtual #3; //Method get:(I)Ljava/lang/String;
5: areturn}}}

有趣的是,两个方法的签名是一模一样的,只有返回类型不同。这个在JVM里面是合法的,不过在Java语言里可不允许。bridge的这个方法不干别的,就只是去调用了下原始的那个方法。

为什么我们需要这个synthetic方法呢,谁会调用它?比如现在有段代码想要调用一个非MyLink类型变量的get(int)方法:

{{{List<?> a = new MyLink();
Object z = a.get(0); }}}

它不能调用返回String的方法,因为List里没这样的方法。为了解释的更清楚一点,我们重写下add方法而不是get方法:

{{{package synthetic;

import java.util.LinkedList;
import java.util.List;

public class SyntheticMethodTest4 {

public static class MyLink extends LinkedList<String> {
@Override
public boolean add(String s) {
return true;
}
}

public static void main(String[] args) {
List a = new MyLink();
a.add("");
a.add(13);
}
} }}}

我们会发现这个bridge方法

{{{public boolean add(java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: checkcast #2; //class java/lang/String
5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z
8: ireturn }}}

它不仅调用了原始的方法,它还进行了类型检查。这个检查是在运行时进行的,并不是由JVM自己来完成。正如你所想,在18行的地方会抛出一个异常:

{{{Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)
at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18) }}}

下次如果你在面试中被问到volatile方法的话,说不定面试官知道的还没你多:-)

译者注:其实作者说到最后也没讲完到底什么是volatile方法,其实volatile方法如篇首所说,是不存在的,所谓的volatile方法就是指bridge方法。由于在修饰符中volatile和bridge是同一个值,在之前版本的javap中存在一个BUG,一个bridge方法在反编译后会显示成volatile,所以存在”volatile方法”的说法。

原创文章转载请注明出处:[Java那些不为人知的特殊方法](http://it.deepinmind.com/java/ ... 5.html)

[英文原文链接](http://www.javacodegeeks.com/2 ... s.html) 查看全部
如果你用过反射并且执行过getDeclaredMethods方法的话,你可能会感到很吃惊。你会发现出现了很多源代码里没有的方法。如果你看一下这些方法的修饰符的话,可能会发现里面有些方法是volatile的。顺便说一句,如果在Java面试里问到“什么是volatile方法?”,你可能会吓出一身冷汗。正确的答案是没有volatile方法。但同时,getDeclaredMethods()或者getMethods()返回的这些方法,Modifier.isVolatile(method.getModifiers())的结果却是true。

immutator的一些用户遇到过这样的问题。他们发现,使用immutator(这个项目探索了Java的一些不为人知的细节)生成的Java代码使用volatile了作为方法的关键字,而这样的代码没法通过编译。结果就是这根本没法用。

这是怎么回事?syntethic和bridge方法又是什么?
可见性

当你创建一个嵌套类的时候,它的私有变量和方法对上层的类是可见的。这个在不可变嵌套式Builder模式中用到了。这是Java语言规范里已经定义好的一个行为。

{{{package synthetic;

public class SyntheticMethodTest1 {
private A aObj = new A();

public class A {
private int i;
}

private class B {
private int i = aObj.i;
}

public static void main(String[] args) {
SyntheticMethodTest1 me = new SyntheticMethodTest1();
me.aObj.i = 1;
B bObj = me.new B();
System.out.println(bObj.i);
}
}}}}

JVM是如何处理这个的?它可不知道什么是内部类或者嵌套类的。JVM对所有的类都一视同仁,它都认为是顶级类。所有类都会被编译成顶级类,而那些内部类编译完后会生成...$... class的类文件。

{{{$ ls -Fart
../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java
SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java}}}

如果你创建一个内部类的话,它会被彻底编译成一个顶级类。

那这些私有变量又是如何被外部类访问的呢?如果它们是个顶级类的私有变量(它们的确也是),那为什么别的类还能直接访问这些变量?

javac是这样解决这个问题的,对于任何private的字段,方法或者构造函数,如果它们也被其它顶层类所使用,就会生成一个synthetic方法。这些synthetic方法是用来访问最初的私有变量/方法/构造函数的。这些方法的生成也很智能:只有确实被外部类用到了,才会生成这样的方法。

{{{package synthetic;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class SyntheticMethodTest2 {

public static class A {
private A(){}
private int x;
private void x(){};
}

public static void main(String[] args) {
A a = new A();
a.x = 2;
a.x();
System.out.println(a.x);
for (Method m : A.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getName());
}
System.out.println("--------------------------");
for (Method m : A.class.getMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
System.out.println("--------------------------");
for( Constructor<?> c : A.class.getDeclaredConstructors() ){
System.out.println(String.format("X", c.getModifiers()) + " " + c.getName());
}
}
} }}}

这些生成的方法的名字取决于具体的实现,最后叫什么也不好说。我只能说在我运行的这个平台上,上述程序的输出是这样的:

{{{2
00001008 access$1
00001008 access$2
00001008 access$3
00000002 x
--------------------------
00000111 void wait
00000011 void wait
00000011 void wait
00000001 boolean equals
00000001 String toString
00000101 int hashCode
00000111 Class getClass
00000111 void notify
00000111 void notifyAll
--------------------------
00000002 synthetic.SyntheticMethodTest2$A
00001000 synthetic.SyntheticMethodTest2$A }}}

在上面这个程序中,我们给变量x赋值,然后又调用了一个同名的方法。这会触发编译器生成对应的synthetic方法。你会看到它生成了三个方法,应该是x变量的setter和getter方法,以及x()方法对应的一个synthetic方法。这些方法并不存在于getMethods方法里返回的列表中,因为它们是synthetic方法,是不能直接被调用的。从这点来看,它们和私有方法差不多。

看一下java.lang.reflect.Modifier里面定义的常量,可以明白这些十六进制的数字代表的是什么:

{{{00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC }}}

列表中有两个是构造方法。还有一个私有方法以及一个synthetic方法。存在这个私有方法是因为我们确实定义了它。而synthetic方法的出现是因为我们从外部类调用了它内部的私有成员。到目前为止,还没有出现过bridge方法。
泛型和继承

到目前为止,看起来还不错。不过我们还没有看到”volatile”方法。

看一下java.lang.reflect.Modifier的源码你会发现0x00000040这个常量被定义了两次。一次是定义成VOLATILE,还有一次是BRIDGE(后者是包内部私有的,并不对外开放)。

想出现volatile方法的话,写个简单的程序就行了:

{{{package synthetic;

import java.lang.reflect.Method;
import java.util.LinkedList;

public class SyntheticMethodTest3 {

public static class MyLink extends LinkedList<String> {
@Override
public String get(int i) {
return "";
}
}

public static void main(String[] args) {

for (Method m : MyLink.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
}
}}}}

这个链表有一个返回String的get(int)方法。先别讨论代码整不整洁的问题了。这只是段示例代码而已。整洁的代码当然也会出现同样的问题,不过越复杂的代码越难定位问题罢了。

输出的结果是这样的:

{{{00000001 String get
00001041 Object get }}}

这里有两个get方法。一个是代码里的那个,另外一个是synthetic和bridge方法。用javap反编译后会是这样的:

{{{public java.lang.String get(int);
Code:
Stack=1, Locals=2, Args_size=2
0: ldc #2; //String
2: areturn
LineNumberTable:
line 12: 0

public java.lang.Object get(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokevirtual #3; //Method get:(I)Ljava/lang/String;
5: areturn}}}

有趣的是,两个方法的签名是一模一样的,只有返回类型不同。这个在JVM里面是合法的,不过在Java语言里可不允许。bridge的这个方法不干别的,就只是去调用了下原始的那个方法。

为什么我们需要这个synthetic方法呢,谁会调用它?比如现在有段代码想要调用一个非MyLink类型变量的get(int)方法:

{{{List<?> a = new MyLink();
Object z = a.get(0); }}}

它不能调用返回String的方法,因为List里没这样的方法。为了解释的更清楚一点,我们重写下add方法而不是get方法:

{{{package synthetic;

import java.util.LinkedList;
import java.util.List;

public class SyntheticMethodTest4 {

public static class MyLink extends LinkedList<String> {
@Override
public boolean add(String s) {
return true;
}
}

public static void main(String[] args) {
List a = new MyLink();
a.add("");
a.add(13);
}
} }}}

我们会发现这个bridge方法

{{{public boolean add(java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: checkcast #2; //class java/lang/String
5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z
8: ireturn }}}

它不仅调用了原始的方法,它还进行了类型检查。这个检查是在运行时进行的,并不是由JVM自己来完成。正如你所想,在18行的地方会抛出一个异常:

{{{Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)
at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18) }}}

下次如果你在面试中被问到volatile方法的话,说不定面试官知道的还没你多:-)

译者注:其实作者说到最后也没讲完到底什么是volatile方法,其实volatile方法如篇首所说,是不存在的,所谓的volatile方法就是指bridge方法。由于在修饰符中volatile和bridge是同一个值,在之前版本的javap中存在一个BUG,一个bridge方法在反编译后会显示成volatile,所以存在”volatile方法”的说法。

原创文章转载请注明出处:[Java那些不为人知的特殊方法](http://it.deepinmind.com/java/ ... 5.html)

[英文原文链接](http://www.javacodegeeks.com/2 ... s.html)

SmileMiner:国人李海峰开发的开源Java机器学习库

综合讨论区besy 发表了文章 • 0 个评论 • 195 次浏览 • 2015-10-10 09:33 • 来自相关话题

**SmileMiner**是一个汇集了各种机器学习算法的纯Java函数库,它是自包含的,仅仅需要Java标准库。主要部件为:Smile,-Math,-Data,-Graph,-Interpolation,-NLP。不可多得的Java机器学习库,其文档和示例都挺赞!

链接:[https://github.com/haifengl/smile](https://github.com/haifengl/smile)

![请输入图片名称](http://img.blog.csdn.net/20151010083309813) 查看全部
**SmileMiner**是一个汇集了各种机器学习算法的纯Java函数库,它是自包含的,仅仅需要Java标准库。主要部件为:Smile,-Math,-Data,-Graph,-Interpolation,-NLP。不可多得的Java机器学习库,其文档和示例都挺赞!

链接:[https://github.com/haifengl/smile](https://github.com/haifengl/smile)

![请输入图片名称](http://img.blog.csdn.net/20151010083309813)

求大神帮忙看看问题出在哪里?编程小白要愁哭了。。。

回复

Java EE开发qiahuangzhang 回复了问题 • 5 人关注 • 4 个回复 • 177 次浏览 • 2017-06-11 22:53 • 来自相关话题

问大家个问题,Java工程bin目录试图窗口不可见

回复

综合讨论区匿名用户 发起了问题 • 1 人关注 • 0 个回复 • 11 次浏览 • 2016-10-18 21:50 • 来自相关话题

常用 Java API 汇总

回复

综合讨论区besy 发起了问题 • 1 人关注 • 0 个回复 • 112 次浏览 • 2016-03-03 09:50 • 来自相关话题

CodeMix 3升级,对标Java版本Vscode,MyEclipse使用者不用换IDE多语言开发

下载|安装|配置|更新momo77 发表了文章 • 0 个评论 • 172 次浏览 • 2019-12-23 15:45 • 来自相关话题

可能很多国内Java开发者还没有使用过**[CodeMix](https://www.myeclipsecn.com/codemix/)**这个神奇的组件,本帖就再来介绍一下。
![请输入图片名称](https://www.evget.com/Content/ ... 76.png)
Codemix是基于Eclipse的插件,可以让你使用到如VS Code一样的Code OSS扩展社区,以及Webclipse 1.x特性。CodeMix可以安装在基于Eclipse的IDE上,从**[MyEclipse](https://www.myeclipsecn.com/)**到Spring工具套件,并且与PDT和PyDev等流行插件兼容。
![请输入图片名称](https://www.evget.com/Content/ ... 77.gif)
CodeMix最近的版本是于本月(2019年12月)11日发布的,版本号为CI 2019.12.11。此版本是CodeMix 3的一个小升级,更新了以下内容:
- **Eclipse 2019-12兼容性。**
CodeMix CI 2019.12.11与Eclipse的12月发行版兼容,您可以将Eclipse所有最新功能和修补程序与CodeMix一起使用。
- **macOS Catalina兼容性。**
默认情况下,macOS Catalina上对“zsh”shell的更改破坏了某些集成。CodeMix最新版将继续使用Bash来保持集成按预期运行。

[双旦钜惠,购MyEclipse、CodeMix折上折,消费满额享好礼>>>](https://www.evget.com/game/christmas/index)

对一个开发人员来讲,IDE的稳定性很重要。既然是插件,体积最好不要过大以免加载缓慢。
官方提供的CodeMix 3的安装环境建议还是挺简单的,个人认为任何一台开发电脑都完全没有问题:
- Eclipse 2019-06 through 4.6 (Neon)
- Eclipse Update Site or Discovery Site Available
- ~300MB 硬盘空间
- 0.5 GB – 2 GB free RAM (如果安装的扩展更多的化可能需要更多)
- Windows 32/64-bit, Linux 32/64-bit, Mac 64-bit
这里说到的Eclipse版本的问题,MyEclipse的使用者就需要[升级到最新版本(Myelcipse2019.12.5)](https://www.myeclipsecn.com/download/)。
## CodeMix 3的安装方式 ##
要从Eclipse Marketplace下载并安装CodeMix,请将上面的按钮拖到正在运行的Eclipse工作区中。此方法需要Marketplace客户端。
或者,你也可以通过更新站点直接从Eclipse安装: http://www.genuitec.com/updates/codemix/ci/ 。
也可以参考这篇**[CodeMix安装教程](https://www.evget.com/article/2018/10/31/28753.html)** 查看全部
可能很多国内Java开发者还没有使用过**[CodeMix](https://www.myeclipsecn.com/codemix/)**这个神奇的组件,本帖就再来介绍一下。
![请输入图片名称](https://www.evget.com/Content/ ... 76.png)
Codemix是基于Eclipse的插件,可以让你使用到如VS Code一样的Code OSS扩展社区,以及Webclipse 1.x特性。CodeMix可以安装在基于Eclipse的IDE上,从**[MyEclipse](https://www.myeclipsecn.com/)**到Spring工具套件,并且与PDT和PyDev等流行插件兼容。
![请输入图片名称](https://www.evget.com/Content/ ... 77.gif)
CodeMix最近的版本是于本月(2019年12月)11日发布的,版本号为CI 2019.12.11。此版本是CodeMix 3的一个小升级,更新了以下内容:
- **Eclipse 2019-12兼容性。**
CodeMix CI 2019.12.11与Eclipse的12月发行版兼容,您可以将Eclipse所有最新功能和修补程序与CodeMix一起使用。
- **macOS Catalina兼容性。**
默认情况下,macOS Catalina上对“zsh”shell的更改破坏了某些集成。CodeMix最新版将继续使用Bash来保持集成按预期运行。

[双旦钜惠,购MyEclipse、CodeMix折上折,消费满额享好礼>>>](https://www.evget.com/game/christmas/index)

对一个开发人员来讲,IDE的稳定性很重要。既然是插件,体积最好不要过大以免加载缓慢。
官方提供的CodeMix 3的安装环境建议还是挺简单的,个人认为任何一台开发电脑都完全没有问题:
- Eclipse 2019-06 through 4.6 (Neon)
- Eclipse Update Site or Discovery Site Available
- ~300MB 硬盘空间
- 0.5 GB – 2 GB free RAM (如果安装的扩展更多的化可能需要更多)
- Windows 32/64-bit, Linux 32/64-bit, Mac 64-bit
这里说到的Eclipse版本的问题,MyEclipse的使用者就需要[升级到最新版本(Myelcipse2019.12.5)](https://www.myeclipsecn.com/download/)。
## CodeMix 3的安装方式 ##
要从Eclipse Marketplace下载并安装CodeMix,请将上面的按钮拖到正在运行的Eclipse工作区中。此方法需要Marketplace客户端。
或者,你也可以通过更新站点直接从Eclipse安装: http://www.genuitec.com/updates/codemix/ci/
也可以参考这篇**[CodeMix安装教程](https://www.evget.com/article/2018/10/31/28753.html)**

MyEclipse数据库教程:使用Java项目查看JPA工作方式

Java EE开发momo77 发表了文章 • 0 个评论 • 231 次浏览 • 2019-11-27 16:57 • 来自相关话题

**建立一个项目**
一般情况,JPA Facet将被添加到Java或Web项目中。在本教程中,您将使用一个简单的Java项目来查看JPA的工作方式。
注意:您可以[下载本教程中开发的项目](https://www.evget.com/resource/detail-demo-14494),然后导入到您的工作区中。
1、单击下拉箭头![请输入图片名称](https://www.evget.com/Content/ ... 53.png),然后选择Java Project。
2、在“Project Name”字段中输入SampleJPAProject,选择默认选项,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 58.gif)
3、单击![请输入图片名称](https://www.evget.com/Content/ ... 46.png),选择MyEclipse Database Explorer打开透视图。
4、在数据库浏览器中,选择MyEclipse Derby连接,然后单击。
![请输入图片名称](https://www.evget.com/Content/ ... 54.gif)
**注意:**在建立数据库连接之前,无法添加JPA Facet,因为需要选择要使用的连接。
5、切换回MyEclipse Java Enterprise透视图,右键单击项目,然后选择**[MyEclipse](https://www.myeclipsecn.com/)** > Project Facets > Install JPA Facet。
6、在目标运行时下拉列表中选择MyEclipse通用Java运行时,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 51.png)
7、从平台下拉列表中选择一个平台,如果JPA实现类型默认为用户库,则选择与所选平台相对应的库。如果未列出任何库,可单击![请输入图片名称](https://www.evget.com/Content/ ... 10.png)下载适当的库。
![请输入图片名称](https://www.evget.com/Content/ ... 16.png)
8、在“Connection”字段中选择MyEclipse Derby,选中“Add driver library to build path”和“Override default schema”复选框,然后从“Schema”下拉列表中选择CLASSICCARS。单击完成。
![请输入图片名称](https://www.evget.com/Content/ ... 24.gif)
现在,项目中已添加了完全配置的JPA Facet,其中包括JPA配置信息/DB连接信息以及添加到项目构建路径中的所有必需的JDBC和JPA库。如果这是一个Web项目,在将项目部署到应用程序服务器上并在其中运行时,所有构建路径的附加内容都将准备好进行部署。
![请输入图片名称](https://www.evget.com/Content/ ... 70.gif)

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

**创建一个Java包**

在下一个步骤中,对数据库表中的数据进行反向工程,并为项目生成实体。在进行逆向工程之前,需要创建一个Java包,并在其中放置这些实体。
1、展开项目,右键单击src文件夹,然后选择New > Package。
![请输入图片名称](https://www.evget.com/Content/ ... 07.gif)
2、在“Name”字段中输入com.myeclipseide.jpa,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 64.gif)

**逆向工程数据库表**

现在已经建立了项目,可以将PRODUCTLINE表反向工程到项目中,并开始使用所生成的实体。
1、右键单击该项目,然后选择JPA Tools > Generate Entities & DAOs。
**注意:**您可以选择使用MyEclipse逆向工程工具或DALI实体生成器。选择,单击“确定”,然后完成向导。本教程使用MyEclipse逆向工程工具。
![请输入图片名称](https://www.evget.com/Content/ ... 96.png)
2、选择PRODUCTLINE表,单击添加,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 42.gif)
在“Java Package”字段中,单击“ Browse”,然后选择先前创建的com.myeclipseide.jpa程序包。选中以下复选框:
- Entity Bean Generation:让MyEclipse生成注释为用作JPA实体的普通Java类。
- Create abstract class;如果您希望自定义生成的类,而不必每次都覆盖更改,则MyEclipse可以生成基本抽象类以及您可以自定义和使用的具体子类。每次进行反向工程时,MyEclipse只会覆盖抽象基类,并在具体子类中保留更改。
- Update persistence.xml:与Hibernate类似,您可以在JPA配置文件中列出正在使用的所有JPA实体。
- Java Data Access Generation:让MyEclipse生成DAO实用程序类,让您可以立即从数据库中保存/查找/更新/删除实体。此代码包含了JPA实体管理器,使得使用实体和数据库变得非常容易。
- Generate Precise findBy Methods:让MyEclipse生成findByXXX方法,其中XXX与反转的实体上的每个属性有关。这样一来,可以使用任何属性作为查找实体的方法,轻松地从数据库访问实体。
- Generate Java Interfaces:选择此选项将创建带有相应DAO实现类的接口类。取消选择此选项仅生成DAO实现类,而没有用于定义接口的单独类。
![请输入图片名称](https://www.evget.com/Content/ ... 15.gif)
3、单击完成。查看通过展开com.myeclipseide.jpa包生成的MyEclipse资源。
![请输入图片名称](https://www.evget.com/Content/ ... 44.gif)
生成的实体描述如下:
- EntityManagerHelper:使用直接JPA时,开发人员需要使用EntityManager class。EntityManager通过提供用于访问管理器的静态方法以及易于调用的最常用操作,此生成的帮助程序类让使用EntityManager的过程变得更加容易。
- IProductline:定义相应DAO实现类的接口的类。
- Productline:此类是表示数据库表PRODUCTLINE的JPA实体(POJO)。该POJO包含PRODUCTLINE表的字段,并表示数据库中的一行。
- ProductlineDAO:此类包含EntityManagerHelper以便为我们提供易于使用的方法,专门用于在数据库中添加/查找/更新和删除产品。
注意:逆向工程完成后,您可以打开“Persistence”透视图,使用某些持久性和数据源工具来分析数据库和项目中的数据。

**编写应用程序**

由于MyEclipse生成了许多代码,所以您可以快速将精力放在“Business Logic”上,或更具体地说是“实际完成工作的代码”。在本部分中,您将编写一个具有main方法的Java类,该方法将Productline插入数据库,对其进行检索、更新并删除。使用此代码,您会发现在应用程序中使用JPA实体是多么容易!
**一、创建一个类**
1、右键单击com.myeclipseide.jpa软件包,然后选择New Class。
2、在“Name”字段中键入RunJPA,选中Public static void main复选框,然后单击“Finish”。
![请输入图片名称](https://www.evget.com/Content/ ... 76.gif)
在构建新类和main方法之后,需要编写代码来操作Productline实例。
**注意:**以下代码看起来很长而且很复杂,这是因为我们试图在一个代码块中显示四个不同的示例。如果您查看每个操作(保存、加载、更新、删除),就会发现它们都不由几行代码组成。
3、将以下代码添加到main方法中,然后按CTRL + S保存。

{{{
/* 1. Create a reference to our ID */
String productLineID = "Men's Shoes";

/* 2. Create a new Productline instance */
Productline newProductline = new Productline(
productLineID,
"Shoes for men.", "Men's Shoes", null);

/* 3. Create a DAO instance to use */
ProductlineDAO dao = new ProductlineDAO();

/* 4. Store our new product line in the DB */
EntityManagerHelper.beginTransaction();
dao.save(newProductline);
EntityManagerHelper.commit();

/* 5. Now retrieve the new product line,
using the ID we created */
Productline loadedProductline = dao.findById(productLineID);

/* 6. Print out the product line information */
System.out.println("*NEW* Product Line
[productLine="
+
loadedProductline.getProductline() + ",
textDescription="
+
loadedProductline.getTextdescription() + ", image="
+
loadedProductline.getImage() + "]");

/*
* 7. Now let's change same value on the product line, and save the
* change
*/
loadedProductline.setTextdescription("Product line for men's shoes.");
EntityManagerHelper.beginTransaction();
dao.save(loadedProductline);
EntityManagerHelper.commit();

/*
* 8. Now let's load the product line from the DB again, and make sure
* it text description changed
*/
Productline secondLoadedProductline =
dao.findById(productLineID);
System.out.println("*REVISED* Product Line ["
+ "productLine=" +
secondLoadedProductline.getProductline()
+ ", textDescription=" +
secondLoadedProductline.getTextdescription()
+ ", image=" +
secondLoadedProductline.getImage() + "]");

/* 9. Now let's delete the product line from the DB */
EntityManagerHelper.beginTransaction();
dao.delete(secondLoadedProductline);
EntityManagerHelper.commit();

/*
* 10. To confirm the deletion, try and load it again and make sure it
* fails
*/
Productline deletedProductline = dao.findById(productLineID);

/*
* We use a simple inlined IF clause to test for null and print
* SUCCESSFUL/FAILED
*/
System.out.println("Productline deletion: "
+ (deletedProductline ==
null ? "SUCCESSFUL" : "FAILED"));
}}}
上面的代码看起来很复杂,但它做了很多简单的事情。例如,如果您只对在数据库中存储新项目感兴趣,则只需要程序中第1-3步中的代码,这相当于(减去注释)三行代码。以下是每个编号部分的细分:
PRODUCTLINE表使用产品线的名称作为主键。为了使本教程更容易理解,我们在字符串中定义了产品线名称,并在代码中多次运用(创建和存储产品线,然后检索两次)。
这将创建由MyEclipse生成的Productline POJO的新实例,并将其插入数据库中。对于本教程而言,这些值并不重要,所以我们只使用示例信息。
这将创建要使用的DAO实例。数据库访问需要DAO(这也是由MyEclipse生成的)。
这让DAO将新的产品系列存储在数据库中。因为要向数据库中写入一些内容,所以将save调用包含在事务中。

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

为了确保使用第1步中定义的ID正确存储了产品系列,我们要求DAO获取产品系列,并将结果分配给一个全新的对象,以完全确保从数据库中加载了什么。(我们可以将值分配回newProductline,但是出于本教程的目的,我们必须清楚地知道对象来源,并且加载的实例之前在代码中不存在)。
这将从已加载的实体中打印出值,以确保它只是存储在数据库中的值。
这将更改刚刚加载的POJO的值,以显示更新记录的工作方式。然后,使用DAO将更改提交回数据库。同样的,此操作被包含在事务中,以确保安全地更改数据库。
与步骤5一样,使用在步骤1中定义的ID从数据库中重新加载记录,以确保更新操作有效。然后打印出POJO值,以确保新描述已保存到数据库中。
这显示了如何从数据库删除记录。同样的,由于这需要更改数据库,因此该代码被包含在事务中。
与第8步和第5步类似,为了证明删除有效,我们尝试使用给定的ID从数据库加载实体。因为我们已经删除了Productline,所以这个操作应该是失败的。从DAO获得结果后,将使用嵌入式IF子句打印一条语句,以确保结果为null。
**二、运行应用程序**
1、右键单击项目,然后选择Run As > Java Application。
2、选择RunJPA应用程序,然后单击“确定”。
![请输入图片名称](https://www.evget.com/Content/ ... 70.png)
输出显示在Console视图中。
![请输入图片名称](https://www.evget.com/Content/ ... 30.jpg)
红色文本是来自MyEclipse中生成的DAO和EntityHelper类的默认日志消息。黑色文本是代码中用于跟踪进度的System.out.println文本。如您所见,第6步中的第一个打印输出和第8步中的更新打印输出都按预期工作。并且查询没有返回Productline,证明删除也很成功。

**资源**
[Oracle JPA注释参考](https://www.oracle.com/technet ... 1.html)
[BEA JPQL参考](https://www.evget.com/resource ... -17577) 查看全部
**建立一个项目**
一般情况,JPA Facet将被添加到Java或Web项目中。在本教程中,您将使用一个简单的Java项目来查看JPA的工作方式。
注意:您可以[下载本教程中开发的项目](https://www.evget.com/resource/detail-demo-14494),然后导入到您的工作区中。
1、单击下拉箭头![请输入图片名称](https://www.evget.com/Content/ ... 53.png),然后选择Java Project。
2、在“Project Name”字段中输入SampleJPAProject,选择默认选项,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 58.gif)
3、单击![请输入图片名称](https://www.evget.com/Content/ ... 46.png),选择MyEclipse Database Explorer打开透视图。
4、在数据库浏览器中,选择MyEclipse Derby连接,然后单击。
![请输入图片名称](https://www.evget.com/Content/ ... 54.gif)
**注意:**在建立数据库连接之前,无法添加JPA Facet,因为需要选择要使用的连接。
5、切换回MyEclipse Java Enterprise透视图,右键单击项目,然后选择**[MyEclipse](https://www.myeclipsecn.com/)** > Project Facets > Install JPA Facet。
6、在目标运行时下拉列表中选择MyEclipse通用Java运行时,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 51.png)
7、从平台下拉列表中选择一个平台,如果JPA实现类型默认为用户库,则选择与所选平台相对应的库。如果未列出任何库,可单击![请输入图片名称](https://www.evget.com/Content/ ... 10.png)下载适当的库。
![请输入图片名称](https://www.evget.com/Content/ ... 16.png)
8、在“Connection”字段中选择MyEclipse Derby,选中“Add driver library to build path”和“Override default schema”复选框,然后从“Schema”下拉列表中选择CLASSICCARS。单击完成。
![请输入图片名称](https://www.evget.com/Content/ ... 24.gif)
现在,项目中已添加了完全配置的JPA Facet,其中包括JPA配置信息/DB连接信息以及添加到项目构建路径中的所有必需的JDBC和JPA库。如果这是一个Web项目,在将项目部署到应用程序服务器上并在其中运行时,所有构建路径的附加内容都将准备好进行部署。
![请输入图片名称](https://www.evget.com/Content/ ... 70.gif)

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

**创建一个Java包**

在下一个步骤中,对数据库表中的数据进行反向工程,并为项目生成实体。在进行逆向工程之前,需要创建一个Java包,并在其中放置这些实体。
1、展开项目,右键单击src文件夹,然后选择New > Package。
![请输入图片名称](https://www.evget.com/Content/ ... 07.gif)
2、在“Name”字段中输入com.myeclipseide.jpa,然后单击“完成”。
![请输入图片名称](https://www.evget.com/Content/ ... 64.gif)

**逆向工程数据库表**

现在已经建立了项目,可以将PRODUCTLINE表反向工程到项目中,并开始使用所生成的实体。
1、右键单击该项目,然后选择JPA Tools > Generate Entities & DAOs。
**注意:**您可以选择使用MyEclipse逆向工程工具或DALI实体生成器。选择,单击“确定”,然后完成向导。本教程使用MyEclipse逆向工程工具。
![请输入图片名称](https://www.evget.com/Content/ ... 96.png)
2、选择PRODUCTLINE表,单击添加,然后单击下一步。
![请输入图片名称](https://www.evget.com/Content/ ... 42.gif)
在“Java Package”字段中,单击“ Browse”,然后选择先前创建的com.myeclipseide.jpa程序包。选中以下复选框:
- Entity Bean Generation:让MyEclipse生成注释为用作JPA实体的普通Java类。
- Create abstract class;如果您希望自定义生成的类,而不必每次都覆盖更改,则MyEclipse可以生成基本抽象类以及您可以自定义和使用的具体子类。每次进行反向工程时,MyEclipse只会覆盖抽象基类,并在具体子类中保留更改。
- Update persistence.xml:与Hibernate类似,您可以在JPA配置文件中列出正在使用的所有JPA实体。
- Java Data Access Generation:让MyEclipse生成DAO实用程序类,让您可以立即从数据库中保存/查找/更新/删除实体。此代码包含了JPA实体管理器,使得使用实体和数据库变得非常容易。
- Generate Precise findBy Methods:让MyEclipse生成findByXXX方法,其中XXX与反转的实体上的每个属性有关。这样一来,可以使用任何属性作为查找实体的方法,轻松地从数据库访问实体。
- Generate Java Interfaces:选择此选项将创建带有相应DAO实现类的接口类。取消选择此选项仅生成DAO实现类,而没有用于定义接口的单独类。
![请输入图片名称](https://www.evget.com/Content/ ... 15.gif)
3、单击完成。查看通过展开com.myeclipseide.jpa包生成的MyEclipse资源。
![请输入图片名称](https://www.evget.com/Content/ ... 44.gif)
生成的实体描述如下:
- EntityManagerHelper:使用直接JPA时,开发人员需要使用EntityManager class。EntityManager通过提供用于访问管理器的静态方法以及易于调用的最常用操作,此生成的帮助程序类让使用EntityManager的过程变得更加容易。
- IProductline:定义相应DAO实现类的接口的类。
- Productline:此类是表示数据库表PRODUCTLINE的JPA实体(POJO)。该POJO包含PRODUCTLINE表的字段,并表示数据库中的一行。
- ProductlineDAO:此类包含EntityManagerHelper以便为我们提供易于使用的方法,专门用于在数据库中添加/查找/更新和删除产品。
注意:逆向工程完成后,您可以打开“Persistence”透视图,使用某些持久性和数据源工具来分析数据库和项目中的数据。

**编写应用程序**

由于MyEclipse生成了许多代码,所以您可以快速将精力放在“Business Logic”上,或更具体地说是“实际完成工作的代码”。在本部分中,您将编写一个具有main方法的Java类,该方法将Productline插入数据库,对其进行检索、更新并删除。使用此代码,您会发现在应用程序中使用JPA实体是多么容易!
**一、创建一个类**
1、右键单击com.myeclipseide.jpa软件包,然后选择New Class。
2、在“Name”字段中键入RunJPA,选中Public static void main复选框,然后单击“Finish”。
![请输入图片名称](https://www.evget.com/Content/ ... 76.gif)
在构建新类和main方法之后,需要编写代码来操作Productline实例。
**注意:**以下代码看起来很长而且很复杂,这是因为我们试图在一个代码块中显示四个不同的示例。如果您查看每个操作(保存、加载、更新、删除),就会发现它们都不由几行代码组成。
3、将以下代码添加到main方法中,然后按CTRL + S保存。

{{{
/* 1. Create a reference to our ID */
String productLineID = "Men's Shoes";

/* 2. Create a new Productline instance */
Productline newProductline = new Productline(
productLineID,
"Shoes for men.", "Men's Shoes", null);

/* 3. Create a DAO instance to use */
ProductlineDAO dao = new ProductlineDAO();

/* 4. Store our new product line in the DB */
EntityManagerHelper.beginTransaction();
dao.save(newProductline);
EntityManagerHelper.commit();

/* 5. Now retrieve the new product line,
using the ID we created */
Productline loadedProductline = dao.findById(productLineID);

/* 6. Print out the product line information */
System.out.println("*NEW* Product Line
[productLine="
+
loadedProductline.getProductline() + ",
textDescription="
+
loadedProductline.getTextdescription() + ", image="
+
loadedProductline.getImage() + "]");

/*
* 7. Now let's change same value on the product line, and save the
* change
*/
loadedProductline.setTextdescription("Product line for men's shoes.");
EntityManagerHelper.beginTransaction();
dao.save(loadedProductline);
EntityManagerHelper.commit();

/*
* 8. Now let's load the product line from the DB again, and make sure
* it text description changed
*/
Productline secondLoadedProductline =
dao.findById(productLineID);
System.out.println("*REVISED* Product Line ["
+ "productLine=" +
secondLoadedProductline.getProductline()
+ ", textDescription=" +
secondLoadedProductline.getTextdescription()
+ ", image=" +
secondLoadedProductline.getImage() + "]");

/* 9. Now let's delete the product line from the DB */
EntityManagerHelper.beginTransaction();
dao.delete(secondLoadedProductline);
EntityManagerHelper.commit();

/*
* 10. To confirm the deletion, try and load it again and make sure it
* fails
*/
Productline deletedProductline = dao.findById(productLineID);

/*
* We use a simple inlined IF clause to test for null and print
* SUCCESSFUL/FAILED
*/
System.out.println("Productline deletion: "
+ (deletedProductline ==
null ? "SUCCESSFUL" : "FAILED"));
}}}
上面的代码看起来很复杂,但它做了很多简单的事情。例如,如果您只对在数据库中存储新项目感兴趣,则只需要程序中第1-3步中的代码,这相当于(减去注释)三行代码。以下是每个编号部分的细分:
PRODUCTLINE表使用产品线的名称作为主键。为了使本教程更容易理解,我们在字符串中定义了产品线名称,并在代码中多次运用(创建和存储产品线,然后检索两次)。
这将创建由MyEclipse生成的Productline POJO的新实例,并将其插入数据库中。对于本教程而言,这些值并不重要,所以我们只使用示例信息。
这将创建要使用的DAO实例。数据库访问需要DAO(这也是由MyEclipse生成的)。
这让DAO将新的产品系列存储在数据库中。因为要向数据库中写入一些内容,所以将save调用包含在事务中。

**[下载MyEclipse>>>](https://www.myeclipsecn.com/download/)**
**[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)**

为了确保使用第1步中定义的ID正确存储了产品系列,我们要求DAO获取产品系列,并将结果分配给一个全新的对象,以完全确保从数据库中加载了什么。(我们可以将值分配回newProductline,但是出于本教程的目的,我们必须清楚地知道对象来源,并且加载的实例之前在代码中不存在)。
这将从已加载的实体中打印出值,以确保它只是存储在数据库中的值。
这将更改刚刚加载的POJO的值,以显示更新记录的工作方式。然后,使用DAO将更改提交回数据库。同样的,此操作被包含在事务中,以确保安全地更改数据库。
与步骤5一样,使用在步骤1中定义的ID从数据库中重新加载记录,以确保更新操作有效。然后打印出POJO值,以确保新描述已保存到数据库中。
这显示了如何从数据库删除记录。同样的,由于这需要更改数据库,因此该代码被包含在事务中。
与第8步和第5步类似,为了证明删除有效,我们尝试使用给定的ID从数据库加载实体。因为我们已经删除了Productline,所以这个操作应该是失败的。从DAO获得结果后,将使用嵌入式IF子句打印一条语句,以确保结果为null。
**二、运行应用程序**
1、右键单击项目,然后选择Run As > Java Application。
2、选择RunJPA应用程序,然后单击“确定”。
![请输入图片名称](https://www.evget.com/Content/ ... 70.png)
输出显示在Console视图中。
![请输入图片名称](https://www.evget.com/Content/ ... 30.jpg)
红色文本是来自MyEclipse中生成的DAO和EntityHelper类的默认日志消息。黑色文本是代码中用于跟踪进度的System.out.println文本。如您所见,第6步中的第一个打印输出和第8步中的更新打印输出都按预期工作。并且查询没有返回Productline,证明删除也很成功。

**资源**
[Oracle JPA注释参考](https://www.oracle.com/technet ... 1.html)
[BEA JPQL参考](https://www.evget.com/resource ... -17577)

Java全栈开发工程师力荐工具MyEclipse&CodeMix年终让利|限时折上折

MyEclipse IDE公告momo77 发表了文章 • 0 个评论 • 125 次浏览 • 2019-11-20 10:11 • 来自相关话题

作为Java开发人员,你是否找到了喜欢的开发工具?
本文介绍的这两款市面最流行、价格最实惠、功能最强大的Java开发神器,一定能让你用一次就爱不释手!

**[MyEclipse——企业级Java EE开发工具](https://www.myeclipsecn.com/)**

提起MyEclipse,从事Java工作或学习的朋友们应该很熟悉,它是Eclispse的进一步扩展,是企业级Java EE开发工具。它包括了完备的编码、调试、测试和发布功能,同时也支持Java Servlet、AJAX、JSP、JSF、Struts、SpringHibernate、EJB3、JDBC数据库链接工具等多项功能,主要用于Java、Java EE及Web开发。
由此可见,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持相当不错。
![请输入图片名称](https://www.evget.com/Content/ ... 61.png)

**[免费试用30天](https://www.myeclipsecn.com/download/)** **[优惠购买正版授权](https://www.evget.com/mall/detail/3016)**

其实网络上对于Java的编译器有着非常大的争端。有的人说IDEA好,也有说MyEclipse强大的。但是在小编看来,工具嘛,个人使用顺手就好啦,没必要硬扯出个输赢。
经常与MyEclipse一起出现的还有CodeMix。

**[CodeMix——代码自动补全插件](https://www.myeclipsecn.com/codemix/)**

CodeMix是Eclipse IDE代码自动补全插件,具有智能代码完成、键盘电源与命令、调试等功能,可以执行从打开文件到运行构建的所有操作,根据语言语义和代码分析,在你输入代码的时候显示内容辅助建议、进行代码自动补全,还能添加断点、找出代码中的错误。由此可见,可能使用CodeMix的人永远都不能理解加班狗的痛苦。
最让Java开发人员喜欢的是,CodeMix与基于Eclipse的IDE和工具兼容(比如MyEclipse),即使是初次使用CodeMixd的人也能在熟悉的环境中快速工作。
重点是,CodeMix解锁了VS Code和Code OSS附加扩展的各种技术。所以,如果你羡慕VS Code的超快速度,一定要带走CodeMix,因为它能增强你的工作流程和开发速度!

**[优惠购买正版授权](https://www.evget.com/mall/detail/4078)**

或许你现在已经心动了,又或许你早就盯上了上述两款工具,但还在观摩等待更实惠的价格。慧都网不仅知你所需,还要给你想要:
[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)
注意,慧都商城中MyEclipse的商业授权包括标准版、专业版、Spring版、Blue版和Bling版:
- 标准版可以满足Jave EE入门开发的需求;
- 专业版除可以满足Jave EE入门开发的需求外,还拥有能应付所有应用程序开发的灵活工具集;
- 而Blue版和Spring版则是在专业版基础上分别增加了完整支持WebSphere和Spring开发的工具集;
- Bling版是Blue版和Spring版的并集。
所以,在购买时一定要根据自己的实际需求选购合适的版本哦!(土豪除外~)
提示:对于Jave EE入门开发的工具集来说,五个版本的MyEclipse都可以满足需求;如果你需要支持WebSphere的完整工具集,可以选择Blue版或Bling版。若您有其他疑问,欢迎**[【联系客服】](https://chat8.live800.com/live ... Bs%3D1)**了解~

**[MyEclipse&CodeMix资源集锦](https://www.evget.com/topic/22)**
视频资源、移动开发/Web开发/数据库教程、各版本更新要点,应有尽有。 查看全部
作为Java开发人员,你是否找到了喜欢的开发工具?
本文介绍的这两款市面最流行、价格最实惠、功能最强大的Java开发神器,一定能让你用一次就爱不释手!

**[MyEclipse——企业级Java EE开发工具](https://www.myeclipsecn.com/)**

提起MyEclipse,从事Java工作或学习的朋友们应该很熟悉,它是Eclispse的进一步扩展,是企业级Java EE开发工具。它包括了完备的编码、调试、测试和发布功能,同时也支持Java Servlet、AJAX、JSP、JSF、Struts、SpringHibernate、EJB3、JDBC数据库链接工具等多项功能,主要用于Java、Java EE及Web开发。
由此可见,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持相当不错。
![请输入图片名称](https://www.evget.com/Content/ ... 61.png)

**[免费试用30天](https://www.myeclipsecn.com/download/)** **[优惠购买正版授权](https://www.evget.com/mall/detail/3016)**

其实网络上对于Java的编译器有着非常大的争端。有的人说IDEA好,也有说MyEclipse强大的。但是在小编看来,工具嘛,个人使用顺手就好啦,没必要硬扯出个输赢。
经常与MyEclipse一起出现的还有CodeMix。

**[CodeMix——代码自动补全插件](https://www.myeclipsecn.com/codemix/)**

CodeMix是Eclipse IDE代码自动补全插件,具有智能代码完成、键盘电源与命令、调试等功能,可以执行从打开文件到运行构建的所有操作,根据语言语义和代码分析,在你输入代码的时候显示内容辅助建议、进行代码自动补全,还能添加断点、找出代码中的错误。由此可见,可能使用CodeMix的人永远都不能理解加班狗的痛苦。
最让Java开发人员喜欢的是,CodeMix与基于Eclipse的IDE和工具兼容(比如MyEclipse),即使是初次使用CodeMixd的人也能在熟悉的环境中快速工作。
重点是,CodeMix解锁了VS Code和Code OSS附加扩展的各种技术。所以,如果你羡慕VS Code的超快速度,一定要带走CodeMix,因为它能增强你的工作流程和开发速度!

**[优惠购买正版授权](https://www.evget.com/mall/detail/4078)**

或许你现在已经心动了,又或许你早就盯上了上述两款工具,但还在观摩等待更实惠的价格。慧都网不仅知你所需,还要给你想要:
[即日起至11月30日,慧都16周年·技术服务月,软件商城优惠券不限量免费领取,购MyEclipse、CodeMix享折上(MyEclipse最高省48元,CodeMix最高省36元)!](https://www.evget.com/game/index/techsrv)
注意,慧都商城中MyEclipse的商业授权包括标准版、专业版、Spring版、Blue版和Bling版:
- 标准版可以满足Jave EE入门开发的需求;
- 专业版除可以满足Jave EE入门开发的需求外,还拥有能应付所有应用程序开发的灵活工具集;
- 而Blue版和Spring版则是在专业版基础上分别增加了完整支持WebSphere和Spring开发的工具集;
- Bling版是Blue版和Spring版的并集。
所以,在购买时一定要根据自己的实际需求选购合适的版本哦!(土豪除外~)
提示:对于Jave EE入门开发的工具集来说,五个版本的MyEclipse都可以满足需求;如果你需要支持WebSphere的完整工具集,可以选择Blue版或Bling版。若您有其他疑问,欢迎**[【联系客服】](https://chat8.live800.com/live ... Bs%3D1)**了解~

**[MyEclipse&CodeMix资源集锦](https://www.evget.com/topic/22)**
视频资源、移动开发/Web开发/数据库教程、各版本更新要点,应有尽有。

【重要通知】Javonet跨语言整合公开课 今日开讲啦!(内附听课教程)

综合讨论区besy 发表了文章 • 0 个评论 • 88 次浏览 • 2018-07-31 09:40 • 来自相关话题

慧都学院Javonet跨语言整合公开课今日下午2点30准点开讲,本文内附听课教程,开课前可免费下载Javonet产品,购买还可享折上折。
![请输入图片名称](https://image.evget.com//Conte ... 53.jpg)

## [Javonet跨语言整合公开课](http://www.evgetedu.com/open/detail/5148) ##

**开课时间:2018/7/31 下午2:30 准时开讲!**
## 【课程亮点】 ##

- 厂商CTO亲自授课,用一节课解决您跨语言之间的壁垒;
- 概况跨语言整合( C++/COM、. NET 和 Java 之间跨语言整合)技术介绍以及如何在安全的环境下加速您的开发项目;
- 从一般的整合概率出发,到具体的解决方案和它的优点,并优化与IT项目以及Javonet使用的最佳场景。
## 【适合人群】 ##

系统架构师;.NET开发人员;Java开发者;系统整合人员;团队领导、IT经理

**[听课教程](https://www.evget.com/article/2018/7/30/28241.html)** 查看全部
慧都学院Javonet跨语言整合公开课今日下午2点30准点开讲,本文内附听课教程,开课前可免费下载Javonet产品,购买还可享折上折。
![请输入图片名称](https://image.evget.com//Conte ... 53.jpg)

## [Javonet跨语言整合公开课](http://www.evgetedu.com/open/detail/5148) ##

**开课时间:2018/7/31 下午2:30 准时开讲!**
## 【课程亮点】 ##

- 厂商CTO亲自授课,用一节课解决您跨语言之间的壁垒;
- 概况跨语言整合( C++/COM、. NET 和 Java 之间跨语言整合)技术介绍以及如何在安全的环境下加速您的开发项目;
- 从一般的整合概率出发,到具体的解决方案和它的优点,并优化与IT项目以及Javonet使用的最佳场景。
## 【适合人群】 ##

系统架构师;.NET开发人员;Java开发者;系统整合人员;团队领导、IT经理

**[听课教程](https://www.evget.com/article/2018/7/30/28241.html)**

【附示例】Java 程 序 员 必 知 的 8 大 排 序

综合讨论区besy 发表了文章 • 0 个评论 • 231 次浏览 • 2015-10-15 11:26 • 来自相关话题

8种排序之间的关系:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 68.png)

## 1、直接插入排序 ##

(1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排

好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数

也是排好顺序的。如此反复循环,直到全部排好顺序。

(2)实例

![请输入图片名称](http://my.csdn.net/uploads/201 ... 87.png)

(3)用java实现

{{{
package com.njue;

public class insertSort {
public insertSort(){
inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=1;i<a.length;i++){
int j=i-1;
temp=a[i];
for(;j>=0&&temp<a[j];j--){
a[j+1]=a[j]; //将大于temp的值整体后移一个单位
}
a[j+1]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 2、希尔排序(最小增量排序) ##

(1)基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 15.png)

(3)用java实现

{{{
public class shellSort {
public shellSort(){
int a[]={1,54,6,3,78,34,12,45,56,100};
double d1=a.length;
int temp=0;
while(true){
d1= Math.ceil(d1/2);
int d=(int) d1;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j=i-d;
temp=a[i];
for(;j>=0&&temp<a[j];j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
if(d==1)
break;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 3.简单选择排序 ##

(1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 19.png)

(3)用java实现

{{{
public class selectSort {
public selectSort(){
int a[]={1,54,6,3,78,34,12,45};
int position=0;
for(int i=0;i<a.length;i++){

int j=i+1;
position=i;
int temp=a[i];
for(;j<a.length;j++){
if(a[j]<temp){
temp=a[j];
position=j;
}
}
a[position]=a[i];
a[i]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 4、 堆排序 ##

(1)基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

(2)实例:

初始序列:46,79,56,38,40,84

建堆:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 48.png)

交换,从堆中踢出最大数

![请输入图片名称](http://my.csdn.net/uploads/201 ... 47.png)

![请输入图片名称](http://my.csdn.net/uploads/201 ... 88.png)

依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。

(3)用java实现

{{{
import java.util.Arrays;

public class HeapSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public HeapSort(){
heapSort(a);
}
public void heapSort(int[] a){
System.out.println("开始排序");
int arrayLength=a.length;
//循环建堆
for(int i=0;i<arrayLength-1;i++){
//建堆

buildMaxHeap(a,arrayLength-1-i);
//交换堆顶和最后一个元素
swap(a,0,arrayLength-1-i);
System.out.println(Arrays.toString(a));
}
}

private void swap(int[] data, int i, int j) {
// TODO Auto-generated method stub
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
//对data数组从0到lastIndex建大顶堆
private void buildMaxHeap(int[] data, int lastIndex) {
// TODO Auto-generated method stub
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i=(lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k=biggerIndex;
}else{
break;
}
}<p align="left">&nbsp;<span> </span>}</p><p align="left">&nbsp;&nbsp;&nbsp; }</p><p align="left">&nbsp;<span style="background-color: white; ">}</span></p>

}}}

## 5.冒泡排序 ##

(1)基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 67.png)

(3)用java实现

{{{
public class bubbleSort {
public bubbleSort(){
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}

}}}

## 6.快速排序 ##

(1)基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 95.png)

(3)用java实现

{{{
public class quickSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public quickSort(){
quick(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; //数组的第一个作为中轴
while (low < high) {
while (low < high && list[high] >= tmp) {

high--;
}
list[low] = list[high]; //比中轴小的记录移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; //比中轴大的记录移到高端
}
list[low] = tmp; //中轴记录到尾
return low; //返回中轴的位置
}
public void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); //将list数组进行一分为二
_quickSort(list, low, middle - 1); //对低字表进行递归排序
_quickSort(list, middle + 1, high); //对高字表进行递归排序
}
}
public void quick(int[] a2) {
if (a2.length > 0) { //查看数组是否为空
_quickSort(a2, 0, a2.length - 1);
}
}
}
}}}

## 7、归并排序 ##

(1)基本排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 91.png)

(3)用java实现

{{{
import java.util.Arrays;

public class mergingSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public mergingSort(){
sort(a,0,a.length-1);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] data, int left, int right) {
// TODO Auto-generated method stub
if(left<right){
//找出中间索引
int center=(left+right)/2;
//对左边数组进行递归
sort(data,left,center);
//对右边数组进行递归
sort(data,center+1,right);
//合并
merge(data,left,center,right);

}
}
public void merge(int[] data, int left, int center, int right) {
// TODO Auto-generated method stub
int [] tmpArr=new int[data.length];
int mid=center+1;
//third记录中间数组的索引
int third=left;
int tmp=left;
while(left<=center&&mid<=right){

//从两个数组中取出最小的放入中间数组
if(data[left]<=data[mid]){
tmpArr[third++]=data[left++];
}else{
tmpArr[third++]=data[mid++];
}
}
//剩余部分依次放入中间数组
while(mid<=right){
tmpArr[third++]=data[mid++];
}
while(left<=center){
tmpArr[third++]=data[left++];
}
//将中间数组中的内容复制回原数组
while(tmp<=right){
data[tmp]=tmpArr[tmp++];
}
System.out.println(Arrays.toString(data));
}

}
}}}

## 8、基数排序 ##

(1)基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 46.png)

(3)用java实现

{{{
import java.util.ArrayList;
import java.util.List;

public class radixSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,101,56,17,18,23,34,15,35,25,53,51};
public radixSort(){
sort(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] array){

//首先确定排序的趟数;
int max=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max){
max=array[i];
}
}

int time=0;
//判断位数;
while(max>0){
max/=10;
time++;
}

//建立10个队列;
List<ArrayList> queue=new ArrayList<ArrayList>();
for(int i=0;i<10;i++){
ArrayList<Integer> queue1=new ArrayList<Integer>();
queue.add(queue1);
}

//进行time次分配和收集;
for(int i=0;i<time;i++){

//分配数组元素;
for(int j=0;j<array.length;j++){
//得到数字的第time+1位数;
int x=array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
ArrayList<Integer> queue2=queue.get(x);
queue2.add(array[j]);
queue.set(x, queue2);
}
int count=0;//元素计数器;
//收集队列元素;
for(int k=0;k<10;k++){
while(queue.get(k).size()>0){
ArrayList<Integer> queue3=queue.get(k);
array[count]=queue3.get(0);
queue3.remove(0);
count++;
}
}
}
}

}
}}}

原文出处:http://blog.csdn.net/without08 ... 97916 查看全部
8种排序之间的关系:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 68.png)

## 1、直接插入排序 ##

(1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排

好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数

也是排好顺序的。如此反复循环,直到全部排好顺序。

(2)实例

![请输入图片名称](http://my.csdn.net/uploads/201 ... 87.png)

(3)用java实现

{{{
package com.njue;

public class insertSort {
public insertSort(){
inta[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=1;i<a.length;i++){
int j=i-1;
temp=a[i];
for(;j>=0&&temp<a[j];j--){
a[j+1]=a[j]; //将大于temp的值整体后移一个单位
}
a[j+1]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 2、希尔排序(最小增量排序) ##

(1)基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 15.png)

(3)用java实现

{{{
public class shellSort {
public shellSort(){
int a[]={1,54,6,3,78,34,12,45,56,100};
double d1=a.length;
int temp=0;
while(true){
d1= Math.ceil(d1/2);
int d=(int) d1;
for(int x=0;x<d;x++){
for(int i=x+d;i<a.length;i+=d){
int j=i-d;
temp=a[i];
for(;j>=0&&temp<a[j];j-=d){
a[j+d]=a[j];
}
a[j+d]=temp;
}
}
if(d==1)
break;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 3.简单选择排序 ##

(1)基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;

然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 19.png)

(3)用java实现

{{{
public class selectSort {
public selectSort(){
int a[]={1,54,6,3,78,34,12,45};
int position=0;
for(int i=0;i<a.length;i++){

int j=i+1;
position=i;
int temp=a[i];
for(;j<a.length;j++){
if(a[j]<temp){
temp=a[j];
position=j;
}
}
a[position]=a[i];
a[i]=temp;
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}
}}}

## 4、 堆排序 ##

(1)基本思想:堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆。在这里只讨论满足前者条件的堆。由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项(大顶堆)。完全二叉树可以很直观地表示堆的结构。堆顶为根,其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的存储序,使之成为一个堆,这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

(2)实例:

初始序列:46,79,56,38,40,84

建堆:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 48.png)

交换,从堆中踢出最大数

![请输入图片名称](http://my.csdn.net/uploads/201 ... 47.png)

![请输入图片名称](http://my.csdn.net/uploads/201 ... 88.png)

依次类推:最后堆中剩余的最后两个结点交换,踢出一个,排序完成。

(3)用java实现

{{{
import java.util.Arrays;

public class HeapSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public HeapSort(){
heapSort(a);
}
public void heapSort(int[] a){
System.out.println("开始排序");
int arrayLength=a.length;
//循环建堆
for(int i=0;i<arrayLength-1;i++){
//建堆

buildMaxHeap(a,arrayLength-1-i);
//交换堆顶和最后一个元素
swap(a,0,arrayLength-1-i);
System.out.println(Arrays.toString(a));
}
}

private void swap(int[] data, int i, int j) {
// TODO Auto-generated method stub
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
//对data数组从0到lastIndex建大顶堆
private void buildMaxHeap(int[] data, int lastIndex) {
// TODO Auto-generated method stub
//从lastIndex处节点(最后一个节点)的父节点开始
for(int i=(lastIndex-1)/2;i>=0;i--){
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while(k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在
if(biggerIndex<lastIndex){
//若果右子节点的值较大
if(data[biggerIndex]<data[biggerIndex+1]){
//biggerIndex总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大的子节点的值
if(data[k]<data[biggerIndex]){
//交换他们
swap(data,k,biggerIndex);
//将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值
k=biggerIndex;
}else{
break;
}
}<p align="left">&nbsp;<span> </span>}</p><p align="left">&nbsp;&nbsp;&nbsp; }</p><p align="left">&nbsp;<span style="background-color: white; ">}</span></p>

}}}

## 5.冒泡排序 ##

(1)基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 67.png)

(3)用java实现

{{{
public class bubbleSort {
public bubbleSort(){
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
int temp=0;
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
}

}}}

## 6.快速排序 ##

(1)基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

(2)实例:

![请输入图片名称](http://my.csdn.net/uploads/201 ... 95.png)

(3)用java实现

{{{
public class quickSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public quickSort(){
quick(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public int getMiddle(int[] list, int low, int high) {
int tmp = list[low]; //数组的第一个作为中轴
while (low < high) {
while (low < high && list[high] >= tmp) {

high--;
}
list[low] = list[high]; //比中轴小的记录移到低端
while (low < high && list[low] <= tmp) {
low++;
}
list[high] = list[low]; //比中轴大的记录移到高端
}
list[low] = tmp; //中轴记录到尾
return low; //返回中轴的位置
}
public void _quickSort(int[] list, int low, int high) {
if (low < high) {
int middle = getMiddle(list, low, high); //将list数组进行一分为二
_quickSort(list, low, middle - 1); //对低字表进行递归排序
_quickSort(list, middle + 1, high); //对高字表进行递归排序
}
}
public void quick(int[] a2) {
if (a2.length > 0) { //查看数组是否为空
_quickSort(a2, 0, a2.length - 1);
}
}
}
}}}

## 7、归并排序 ##

(1)基本排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 91.png)

(3)用java实现

{{{
import java.util.Arrays;

public class mergingSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51};
public mergingSort(){
sort(a,0,a.length-1);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] data, int left, int right) {
// TODO Auto-generated method stub
if(left<right){
//找出中间索引
int center=(left+right)/2;
//对左边数组进行递归
sort(data,left,center);
//对右边数组进行递归
sort(data,center+1,right);
//合并
merge(data,left,center,right);

}
}
public void merge(int[] data, int left, int center, int right) {
// TODO Auto-generated method stub
int [] tmpArr=new int[data.length];
int mid=center+1;
//third记录中间数组的索引
int third=left;
int tmp=left;
while(left<=center&&mid<=right){

//从两个数组中取出最小的放入中间数组
if(data[left]<=data[mid]){
tmpArr[third++]=data[left++];
}else{
tmpArr[third++]=data[mid++];
}
}
//剩余部分依次放入中间数组
while(mid<=right){
tmpArr[third++]=data[mid++];
}
while(left<=center){
tmpArr[third++]=data[left++];
}
//将中间数组中的内容复制回原数组
while(tmp<=right){
data[tmp]=tmpArr[tmp++];
}
System.out.println(Arrays.toString(data));
}

}
}}}

## 8、基数排序 ##

(1)基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

(2)实例:
![请输入图片名称](http://my.csdn.net/uploads/201 ... 46.png)

(3)用java实现

{{{
import java.util.ArrayList;
import java.util.List;

public class radixSort {
int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,101,56,17,18,23,34,15,35,25,53,51};
public radixSort(){
sort(a);
for(int i=0;i<a.length;i++)
System.out.println(a[i]);
}
public void sort(int[] array){

//首先确定排序的趟数;
int max=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max){
max=array[i];
}
}

int time=0;
//判断位数;
while(max>0){
max/=10;
time++;
}

//建立10个队列;
List<ArrayList> queue=new ArrayList<ArrayList>();
for(int i=0;i<10;i++){
ArrayList<Integer> queue1=new ArrayList<Integer>();
queue.add(queue1);
}

//进行time次分配和收集;
for(int i=0;i<time;i++){

//分配数组元素;
for(int j=0;j<array.length;j++){
//得到数字的第time+1位数;
int x=array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
ArrayList<Integer> queue2=queue.get(x);
queue2.add(array[j]);
queue.set(x, queue2);
}
int count=0;//元素计数器;
//收集队列元素;
for(int k=0;k<10;k++){
while(queue.get(k).size()>0){
ArrayList<Integer> queue3=queue.get(k);
array[count]=queue3.get(0);
queue3.remove(0);
count++;
}
}
}
}

}
}}}

原文出处:http://blog.csdn.net/without08 ... 97916

【干货分享】Java那些不为人知的特殊方法

综合讨论区besy 发表了文章 • 0 个评论 • 128 次浏览 • 2015-10-14 16:01 • 来自相关话题

如果你用过反射并且执行过getDeclaredMethods方法的话,你可能会感到很吃惊。你会发现出现了很多源代码里没有的方法。如果你看一下这些方法的修饰符的话,可能会发现里面有些方法是volatile的。顺便说一句,如果在Java面试里问到“什么是volatile方法?”,你可能会吓出一身冷汗。正确的答案是没有volatile方法。但同时,getDeclaredMethods()或者getMethods()返回的这些方法,Modifier.isVolatile(method.getModifiers())的结果却是true。

immutator的一些用户遇到过这样的问题。他们发现,使用immutator(这个项目探索了Java的一些不为人知的细节)生成的Java代码使用volatile了作为方法的关键字,而这样的代码没法通过编译。结果就是这根本没法用。

这是怎么回事?syntethic和bridge方法又是什么?
可见性

当你创建一个嵌套类的时候,它的私有变量和方法对上层的类是可见的。这个在不可变嵌套式Builder模式中用到了。这是Java语言规范里已经定义好的一个行为。

{{{package synthetic;

public class SyntheticMethodTest1 {
private A aObj = new A();

public class A {
private int i;
}

private class B {
private int i = aObj.i;
}

public static void main(String[] args) {
SyntheticMethodTest1 me = new SyntheticMethodTest1();
me.aObj.i = 1;
B bObj = me.new B();
System.out.println(bObj.i);
}
}}}}

JVM是如何处理这个的?它可不知道什么是内部类或者嵌套类的。JVM对所有的类都一视同仁,它都认为是顶级类。所有类都会被编译成顶级类,而那些内部类编译完后会生成...$... class的类文件。

{{{$ ls -Fart
../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java
SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java}}}

如果你创建一个内部类的话,它会被彻底编译成一个顶级类。

那这些私有变量又是如何被外部类访问的呢?如果它们是个顶级类的私有变量(它们的确也是),那为什么别的类还能直接访问这些变量?

javac是这样解决这个问题的,对于任何private的字段,方法或者构造函数,如果它们也被其它顶层类所使用,就会生成一个synthetic方法。这些synthetic方法是用来访问最初的私有变量/方法/构造函数的。这些方法的生成也很智能:只有确实被外部类用到了,才会生成这样的方法。

{{{package synthetic;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class SyntheticMethodTest2 {

public static class A {
private A(){}
private int x;
private void x(){};
}

public static void main(String[] args) {
A a = new A();
a.x = 2;
a.x();
System.out.println(a.x);
for (Method m : A.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getName());
}
System.out.println("--------------------------");
for (Method m : A.class.getMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
System.out.println("--------------------------");
for( Constructor<?> c : A.class.getDeclaredConstructors() ){
System.out.println(String.format("X", c.getModifiers()) + " " + c.getName());
}
}
} }}}

这些生成的方法的名字取决于具体的实现,最后叫什么也不好说。我只能说在我运行的这个平台上,上述程序的输出是这样的:

{{{2
00001008 access$1
00001008 access$2
00001008 access$3
00000002 x
--------------------------
00000111 void wait
00000011 void wait
00000011 void wait
00000001 boolean equals
00000001 String toString
00000101 int hashCode
00000111 Class getClass
00000111 void notify
00000111 void notifyAll
--------------------------
00000002 synthetic.SyntheticMethodTest2$A
00001000 synthetic.SyntheticMethodTest2$A }}}

在上面这个程序中,我们给变量x赋值,然后又调用了一个同名的方法。这会触发编译器生成对应的synthetic方法。你会看到它生成了三个方法,应该是x变量的setter和getter方法,以及x()方法对应的一个synthetic方法。这些方法并不存在于getMethods方法里返回的列表中,因为它们是synthetic方法,是不能直接被调用的。从这点来看,它们和私有方法差不多。

看一下java.lang.reflect.Modifier里面定义的常量,可以明白这些十六进制的数字代表的是什么:

{{{00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC }}}

列表中有两个是构造方法。还有一个私有方法以及一个synthetic方法。存在这个私有方法是因为我们确实定义了它。而synthetic方法的出现是因为我们从外部类调用了它内部的私有成员。到目前为止,还没有出现过bridge方法。
泛型和继承

到目前为止,看起来还不错。不过我们还没有看到”volatile”方法。

看一下java.lang.reflect.Modifier的源码你会发现0x00000040这个常量被定义了两次。一次是定义成VOLATILE,还有一次是BRIDGE(后者是包内部私有的,并不对外开放)。

想出现volatile方法的话,写个简单的程序就行了:

{{{package synthetic;

import java.lang.reflect.Method;
import java.util.LinkedList;

public class SyntheticMethodTest3 {

public static class MyLink extends LinkedList<String> {
@Override
public String get(int i) {
return "";
}
}

public static void main(String[] args) {

for (Method m : MyLink.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
}
}}}}

这个链表有一个返回String的get(int)方法。先别讨论代码整不整洁的问题了。这只是段示例代码而已。整洁的代码当然也会出现同样的问题,不过越复杂的代码越难定位问题罢了。

输出的结果是这样的:

{{{00000001 String get
00001041 Object get }}}

这里有两个get方法。一个是代码里的那个,另外一个是synthetic和bridge方法。用javap反编译后会是这样的:

{{{public java.lang.String get(int);
Code:
Stack=1, Locals=2, Args_size=2
0: ldc #2; //String
2: areturn
LineNumberTable:
line 12: 0

public java.lang.Object get(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokevirtual #3; //Method get:(I)Ljava/lang/String;
5: areturn}}}

有趣的是,两个方法的签名是一模一样的,只有返回类型不同。这个在JVM里面是合法的,不过在Java语言里可不允许。bridge的这个方法不干别的,就只是去调用了下原始的那个方法。

为什么我们需要这个synthetic方法呢,谁会调用它?比如现在有段代码想要调用一个非MyLink类型变量的get(int)方法:

{{{List<?> a = new MyLink();
Object z = a.get(0); }}}

它不能调用返回String的方法,因为List里没这样的方法。为了解释的更清楚一点,我们重写下add方法而不是get方法:

{{{package synthetic;

import java.util.LinkedList;
import java.util.List;

public class SyntheticMethodTest4 {

public static class MyLink extends LinkedList<String> {
@Override
public boolean add(String s) {
return true;
}
}

public static void main(String[] args) {
List a = new MyLink();
a.add("");
a.add(13);
}
} }}}

我们会发现这个bridge方法

{{{public boolean add(java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: checkcast #2; //class java/lang/String
5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z
8: ireturn }}}

它不仅调用了原始的方法,它还进行了类型检查。这个检查是在运行时进行的,并不是由JVM自己来完成。正如你所想,在18行的地方会抛出一个异常:

{{{Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)
at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18) }}}

下次如果你在面试中被问到volatile方法的话,说不定面试官知道的还没你多:-)

译者注:其实作者说到最后也没讲完到底什么是volatile方法,其实volatile方法如篇首所说,是不存在的,所谓的volatile方法就是指bridge方法。由于在修饰符中volatile和bridge是同一个值,在之前版本的javap中存在一个BUG,一个bridge方法在反编译后会显示成volatile,所以存在”volatile方法”的说法。

原创文章转载请注明出处:[Java那些不为人知的特殊方法](http://it.deepinmind.com/java/ ... 5.html)

[英文原文链接](http://www.javacodegeeks.com/2 ... s.html) 查看全部
如果你用过反射并且执行过getDeclaredMethods方法的话,你可能会感到很吃惊。你会发现出现了很多源代码里没有的方法。如果你看一下这些方法的修饰符的话,可能会发现里面有些方法是volatile的。顺便说一句,如果在Java面试里问到“什么是volatile方法?”,你可能会吓出一身冷汗。正确的答案是没有volatile方法。但同时,getDeclaredMethods()或者getMethods()返回的这些方法,Modifier.isVolatile(method.getModifiers())的结果却是true。

immutator的一些用户遇到过这样的问题。他们发现,使用immutator(这个项目探索了Java的一些不为人知的细节)生成的Java代码使用volatile了作为方法的关键字,而这样的代码没法通过编译。结果就是这根本没法用。

这是怎么回事?syntethic和bridge方法又是什么?
可见性

当你创建一个嵌套类的时候,它的私有变量和方法对上层的类是可见的。这个在不可变嵌套式Builder模式中用到了。这是Java语言规范里已经定义好的一个行为。

{{{package synthetic;

public class SyntheticMethodTest1 {
private A aObj = new A();

public class A {
private int i;
}

private class B {
private int i = aObj.i;
}

public static void main(String[] args) {
SyntheticMethodTest1 me = new SyntheticMethodTest1();
me.aObj.i = 1;
B bObj = me.new B();
System.out.println(bObj.i);
}
}}}}

JVM是如何处理这个的?它可不知道什么是内部类或者嵌套类的。JVM对所有的类都一视同仁,它都认为是顶级类。所有类都会被编译成顶级类,而那些内部类编译完后会生成...$... class的类文件。

{{{$ ls -Fart
../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java
SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java}}}

如果你创建一个内部类的话,它会被彻底编译成一个顶级类。

那这些私有变量又是如何被外部类访问的呢?如果它们是个顶级类的私有变量(它们的确也是),那为什么别的类还能直接访问这些变量?

javac是这样解决这个问题的,对于任何private的字段,方法或者构造函数,如果它们也被其它顶层类所使用,就会生成一个synthetic方法。这些synthetic方法是用来访问最初的私有变量/方法/构造函数的。这些方法的生成也很智能:只有确实被外部类用到了,才会生成这样的方法。

{{{package synthetic;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class SyntheticMethodTest2 {

public static class A {
private A(){}
private int x;
private void x(){};
}

public static void main(String[] args) {
A a = new A();
a.x = 2;
a.x();
System.out.println(a.x);
for (Method m : A.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getName());
}
System.out.println("--------------------------");
for (Method m : A.class.getMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
System.out.println("--------------------------");
for( Constructor<?> c : A.class.getDeclaredConstructors() ){
System.out.println(String.format("X", c.getModifiers()) + " " + c.getName());
}
}
} }}}

这些生成的方法的名字取决于具体的实现,最后叫什么也不好说。我只能说在我运行的这个平台上,上述程序的输出是这样的:

{{{2
00001008 access$1
00001008 access$2
00001008 access$3
00000002 x
--------------------------
00000111 void wait
00000011 void wait
00000011 void wait
00000001 boolean equals
00000001 String toString
00000101 int hashCode
00000111 Class getClass
00000111 void notify
00000111 void notifyAll
--------------------------
00000002 synthetic.SyntheticMethodTest2$A
00001000 synthetic.SyntheticMethodTest2$A }}}

在上面这个程序中,我们给变量x赋值,然后又调用了一个同名的方法。这会触发编译器生成对应的synthetic方法。你会看到它生成了三个方法,应该是x变量的setter和getter方法,以及x()方法对应的一个synthetic方法。这些方法并不存在于getMethods方法里返回的列表中,因为它们是synthetic方法,是不能直接被调用的。从这点来看,它们和私有方法差不多。

看一下java.lang.reflect.Modifier里面定义的常量,可以明白这些十六进制的数字代表的是什么:

{{{00001008 SYNTHETIC|STATIC
00000002 PRIVATE
00000111 NATIVE|FINAL|PUBLIC
00000011 FINAL|PUBLIC
00000001 PUBLIC
00001000 SYNTHETIC }}}

列表中有两个是构造方法。还有一个私有方法以及一个synthetic方法。存在这个私有方法是因为我们确实定义了它。而synthetic方法的出现是因为我们从外部类调用了它内部的私有成员。到目前为止,还没有出现过bridge方法。
泛型和继承

到目前为止,看起来还不错。不过我们还没有看到”volatile”方法。

看一下java.lang.reflect.Modifier的源码你会发现0x00000040这个常量被定义了两次。一次是定义成VOLATILE,还有一次是BRIDGE(后者是包内部私有的,并不对外开放)。

想出现volatile方法的话,写个简单的程序就行了:

{{{package synthetic;

import java.lang.reflect.Method;
import java.util.LinkedList;

public class SyntheticMethodTest3 {

public static class MyLink extends LinkedList<String> {
@Override
public String get(int i) {
return "";
}
}

public static void main(String[] args) {

for (Method m : MyLink.class.getDeclaredMethods()) {
System.out.println(String.format("X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());
}
}
}}}}

这个链表有一个返回String的get(int)方法。先别讨论代码整不整洁的问题了。这只是段示例代码而已。整洁的代码当然也会出现同样的问题,不过越复杂的代码越难定位问题罢了。

输出的结果是这样的:

{{{00000001 String get
00001041 Object get }}}

这里有两个get方法。一个是代码里的那个,另外一个是synthetic和bridge方法。用javap反编译后会是这样的:

{{{public java.lang.String get(int);
Code:
Stack=1, Locals=2, Args_size=2
0: ldc #2; //String
2: areturn
LineNumberTable:
line 12: 0

public java.lang.Object get(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: iload_1
2: invokevirtual #3; //Method get:(I)Ljava/lang/String;
5: areturn}}}

有趣的是,两个方法的签名是一模一样的,只有返回类型不同。这个在JVM里面是合法的,不过在Java语言里可不允许。bridge的这个方法不干别的,就只是去调用了下原始的那个方法。

为什么我们需要这个synthetic方法呢,谁会调用它?比如现在有段代码想要调用一个非MyLink类型变量的get(int)方法:

{{{List<?> a = new MyLink();
Object z = a.get(0); }}}

它不能调用返回String的方法,因为List里没这样的方法。为了解释的更清楚一点,我们重写下add方法而不是get方法:

{{{package synthetic;

import java.util.LinkedList;
import java.util.List;

public class SyntheticMethodTest4 {

public static class MyLink extends LinkedList<String> {
@Override
public boolean add(String s) {
return true;
}
}

public static void main(String[] args) {
List a = new MyLink();
a.add("");
a.add(13);
}
} }}}

我们会发现这个bridge方法

{{{public boolean add(java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: checkcast #2; //class java/lang/String
5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z
8: ireturn }}}

它不仅调用了原始的方法,它还进行了类型检查。这个检查是在运行时进行的,并不是由JVM自己来完成。正如你所想,在18行的地方会抛出一个异常:

{{{Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)
at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18) }}}

下次如果你在面试中被问到volatile方法的话,说不定面试官知道的还没你多:-)

译者注:其实作者说到最后也没讲完到底什么是volatile方法,其实volatile方法如篇首所说,是不存在的,所谓的volatile方法就是指bridge方法。由于在修饰符中volatile和bridge是同一个值,在之前版本的javap中存在一个BUG,一个bridge方法在反编译后会显示成volatile,所以存在”volatile方法”的说法。

原创文章转载请注明出处:[Java那些不为人知的特殊方法](http://it.deepinmind.com/java/ ... 5.html)

[英文原文链接](http://www.javacodegeeks.com/2 ... s.html)

SmileMiner:国人李海峰开发的开源Java机器学习库

综合讨论区besy 发表了文章 • 0 个评论 • 195 次浏览 • 2015-10-10 09:33 • 来自相关话题

**SmileMiner**是一个汇集了各种机器学习算法的纯Java函数库,它是自包含的,仅仅需要Java标准库。主要部件为:Smile,-Math,-Data,-Graph,-Interpolation,-NLP。不可多得的Java机器学习库,其文档和示例都挺赞!

链接:[https://github.com/haifengl/smile](https://github.com/haifengl/smile)

![请输入图片名称](http://img.blog.csdn.net/20151010083309813) 查看全部
**SmileMiner**是一个汇集了各种机器学习算法的纯Java函数库,它是自包含的,仅仅需要Java标准库。主要部件为:Smile,-Math,-Data,-Graph,-Interpolation,-NLP。不可多得的Java机器学习库,其文档和示例都挺赞!

链接:[https://github.com/haifengl/smile](https://github.com/haifengl/smile)

![请输入图片名称](http://img.blog.csdn.net/20151010083309813)