新型液流電池可發電與供氫,電動車與氫燃料車都適用

電池電動車與氫燃料電池車都有望成為新一代交通主力,但這兩種車款各採用不同的「充電方式」,一種是電力、一種是補充氫氣,各國得針對兩種不同的車系分別打造管線與「加油站」,而近日英國格拉斯哥大學打造新型液流電池,不僅可讓汽車在幾秒內完成燃料補充,還可以釋放電力與氫氣、完美解決兩種電動車系統不相容的狀況。

液流電池(flow battery)由兩個電解質槽組成,充放電時電解質會被幫補到中間的發電室,而發電室也會以薄膜隔開兩種溶液、形成兩個電極,最後產生離子交換來發電,而由於兩種電解質是分開存放,不會有電解質相互滲漏與自身放電等安全性問題,是一種良好的儲能生力軍。

只是液流電池體積龐大,即使該電池具有安全性與穩定性高等優點,仍不適合用於 3C 產品與電動車,目前大多研究團隊都是想把液流電池用在再生能源儲能系統。

而格拉斯哥大學這次想將突破以往液流電池無法用在汽車的印象,並成功透過奈米粒子溶液打造新型液流電池,其中團隊所用的電解質是一種奈米懸浮液(suspension),每個奈米粒子都可以當成一顆小型電池,儲存能量更是一般液流電池的 10 倍,還能以電力或氫氣的形式釋放。

且由於液流電池主要以液態電解質驅動,團隊更指出,新型液流電池可在幾秒內完成移除舊液體、補充新電解質,因此該系統的「充電」時間可跟一般汽油車一樣,大大縮短電動車的充電速度。

格拉斯哥大學 Regius Chair of Chemistry 教授 Leroy(Lee)Cronin 表示,若再生能源想要有效運作,還需要儲存容量、靈活性高的儲能系統來幫忙解決間歇性能源與電力尖峰等問題,而團隊提出的新型化學充電方式,除了可用在儲能系統,還可應用在電動車中。

該研究將有助於未來液流電池的應用,有望縮短液流電池與大規模商業化的距離。團隊也指出,新型液流電池的能量密度相當高,可提升將來電動車的續航里程與儲能系統的儲存容量,目前研究已發表在《》。

(首圖來源:。文/DaisyChuang)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

Java 從入門到進階之路(二十三)

在之前的文章我們介紹了一下 Java 中的  集合框架中的Collection 的迭代器 Iterator,本章我們來看一下 Java 集合框架中的Collection 的泛型。

在講泛型之前我們先來看下面一段代碼:

 1 public class Main {
 2     public static void main(String[] args) {
 3         Point point = new Point(1, 2);
 4 
 5         point.setX(2);
 6         int ix = point.getX();
 7         System.out.println(ix); // (2, 2)
 8 
 9         /**
10          * 如果想要 x 值變為 double 類型則可以強轉為 double 類型
11          * */
12         point.setX(2);
13         double dx = (double) point.getX();
14         System.out.println(dx); // 2.0
15     }
16 }
17 
18 class Point {
19     private int x;
20     private int y;
21 
22     public Point(int x, int y) {
23         this.x = x;
24         this.y = y;
25     }
26 
27     public int getX() {
28         return x;
29     }
30 
31     public void setX(int x) {
32         this.x = x;
33     }
34 
35     public int getY() {
36         return y;
37     }
38 
39     public void setY(int y) {
40         this.y = y;
41     }
42 
43     @Override
44     public String toString() {
45         return "(" + x + ", " + y + ")";
46     }
47 }

上面的代碼我們之前的文章講過,我們可以通過傳入 x 和 y 值來定義 Point 點,如果我們想要 double 類型的點時需要造型為 double 類型,那我要定義漢字類型的呢?那就造型成 String 類型,這就很麻煩,每次都需要自己來造型,有種鞋不合腳的感覺,那能不能定義我想要什麼類型就是什麼類型呢,如下:

 1 public class Main {
 2     public static void main(String[] args) {
 3         Point<Integer> point1 = new Point<Integer>(1, 2); // 必須是包裝類
 4         point1.setX(1);
 5         System.out.println(point1.getX()); // 1
 6 
 7         Point<Double> point2 = new Point<Double>(1.1, 2.1); // 必須是包裝類
 8         point2.setX(1.2);
 9         System.out.println(point2.getX()); // 1.2
10 
11         Point<String> point3 = new Point<String>("一", "二"); // 必須是包裝類
12         point3.setX("三");
13         System.out.println(point3.getX()); //
14     }
15 }
16 
17 /**
18  * 泛型
19  * 又稱參數化類型,是將當前類的屬性的類型,方法參數的類型及方法
20  * 返回值的類型的定義權移交給使用者,
21  * 使用者在創建當前類的同時將泛型的試劑類型傳入
22  * 数字和字母組合,数字不能開頭
23  */
24 class Point<T> { // 定義為泛型 T 類型
25     private T x;
26     private T y;
27 
28     public Point(T x, T y) {
29         this.x = x;
30         this.y = y;
31     }
32 
33     public T getX() {
34         return x;
35     }
36 
37     public void setX(T x) {
38         this.x = x;
39     }
40 
41     public T getY() {
42         return y;
43     }
44 
45     public void setY(T y) {
46         this.y = y;
47     }
48 
49     @Override
50     public String toString() {
51         return "(" + x + ", " + y + ")";
52     }
53 }

從上面的代碼中,我們定義了一個 T 的類型 Point,當我們要實例化該類時,根據自己的需求傳入想要的包裝類類型即可,這樣就滿足了不同的需求,各取所需。 

泛型從底層來說其實就是 Object,定義了泛型只是編譯器在做一些驗證工作,當我們對泛型類型設置值時,會檢查是否滿足類型要求,當我們獲取一個泛型類型的值時,會自動進行類型轉換。

在平時我們是很少自己來定義泛型的,泛型是用來約束集合中元素的類型,如下:

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.Iterator;
 4 
 5 public class Main {
 6     public static void main(String[] args) {
 7         Collection<String> collection = new ArrayList<String>(); // 只能添加 String 類型的元素
 8         collection.add("one");
 9         collection.add("two");
10         collection.add("thee");
11         collection.add("four");
12         // collection.add(1); // 編譯錯誤
13         for (String string : collection) {
14             System.out.println(string); // one two three four
15         }
16         Iterator<String> iterator = collection.iterator();
17         while (iterator.hasNext()) {
18             // String string = (String) iterator.next(); 不需要再造型
19             String string = iterator.next();
20             System.out.println(string); // one two three four
21         }
22     }
23 }

  

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

Spring Boot入門系列(十八)整合mybatis,使用註解的方式實現增刪改查

之前介紹了Spring Boot 整合mybatis 使用xml配置的方式實現增刪改查,還介紹了自定義mapper 實現複雜多表關聯查詢。雖然目前 mybatis 使用xml 配置的方式 已經極大減輕了配置的複雜度,支持 generator 插件 根據表結構自動生成實體類、配置文件和dao層代碼,減輕很大一部分開發量;但是 java 註解的運用發展到今天。約定取代配置的規範已經深入人心。開發者還是傾向於使用註解解決一切問題,註解版最大的特點是具體的 SQL 文件需要寫在 Mapper 類中,取消了 Mapper 的 XML 配置 。這樣不用任何配置文件,就可以簡單配置輕鬆上手。所以今天就介紹Spring Boot 整合mybatis 使用註解的方式實現數據庫操作 。

Spring Boot 整合mybatis 使用xml配置版之前已經介紹過了,不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html。

 

一、整合Mybatis

Spring Boot  整合Mybatis 的步驟都是一樣的,已經熟悉的同學可以略過。

1、pom.xml增加mybatis相關依賴

我們只需要加上pom.xml文件這些依賴即可。

       <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <!-- pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- druid 數據庫連接框架-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>

 

2、application.properties配置數據連接

application.properties中需要增加mybatis相關的數據庫配置。

############################################################
# 數據源相關配置,這裏用的是阿里的druid 數據源
############################################################
spring.datasource.url=jdbc:mysql://localhost:3306/zwz_test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.stat-view-servlet.allow=true

############################################################
# mybatis 相關配置
############################################################
mybatis.type-aliases-package=com.weiz.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
mapper.mappers=com.weiz.utils.MyMapper    #這個MyMapper 就是我之前創建的mapper統一接口。後面所有的mapper類都會繼承這個接口
mapper.not-empty=false
mapper.identity=MYSQL
# 分頁框架
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql

這裏的配置有點多,不過最基本的配置都在這。

 

3、在啟動主類添加掃描器

在SpringBootStarterApplication 啟動類中增加包掃描器。

@SpringBootApplication
//掃描 mybatis mapper 包路徑
@MapperScan(basePackages = "com.weiz.mapper") // 這一步別忘了。
//掃描 所有需要的包, 包含一些自用的工具類包 所在的路徑
@ComponentScan(basePackages = {"com.weiz","org.n3r.idworker"})
public class SpringBootStarterApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootStarterApplication.class, args);
}

}

注意:這一步別忘了,需要在SpringBootStarterApplication 啟動類中增加包掃描器,自動掃描加載com.weiz.mapper 裏面的mapper 類。

 

以上,就把Mybatis 整合到項目中了。 接下來就是創建表和pojo類,mybatis提供了強大的自動生成功能。只需簡單幾步就能生成pojo 類和mapper。

 

二、代碼自動生成工具

Mybatis 整合完之後,接下來就是創建表和pojo類,mybatis提供了強大的自動生成功能的插件。mybatis generator插件只需簡單幾步就能生成pojo 類和mapper。操作步驟和xml 配置版也是類似的,唯一要注意的是 generatorConfig.xml 的部分配置,要配置按註解的方式生成mapper 。

1、增加generatorConfig.xml配置文件

在resources 文件下創建 generatorConfig.xml 文件。此配置文件獨立於項目,只是給自動生成工具類的配置文件,具體配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="DB2Tables"  targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自動生成的註釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--數據庫鏈接URL,用戶名、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/zwz_test" userId="root" password="root">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成模型的包名和位置-->
        <javaModelGenerator targetPackage="com.weiz.pojo" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成映射文件的包名和位置-->
        <sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO的包名和位置-->
        <!-- XMLMAPPER生成xml映射文件, ANNOTATEDMAPPER生成的dao採用註解來寫sql -->
        <javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="com.weiz.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名-->
        <table tableName="sys_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
    </context>
</generatorConfiguration>

注意:

這裏的配置 <javaClientGenerator type=”ANNOTATEDMAPPER” targetPackage=”com.weiz.mapper” targetProject=”src/main/java”>

type 的值很重要:
  XMLMAPPER : 表示生成xml映射文件。

  ANNOTATEDMAPPER: 表示生成的mapper 採用註解來寫sql。

 

2、數據庫User表

需要在數據庫中創建相應的表。這個表結構很簡單,就是普通的用戶表sys_user

CREATE TABLE `sys_user` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `nickname` varchar(64) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  `job` int(11) DEFAULT NULL,
  `face_image` varchar(6000) DEFAULT NULL,
  `province` varchar(64) DEFAULT NULL,
  `city` varchar(64) DEFAULT NULL,
  `district` varchar(64) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `auth_salt` varchar(64) DEFAULT NULL,
  `last_login_ip` varchar(64) DEFAULT NULL,
  `last_login_time` datetime DEFAULT NULL,
  `is_delete` int(11) DEFAULT NULL,
  `regist_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 

3、創建GeneratorDisplay類

package com.weiz.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorDisplay {

    public void generator() throws Exception{

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("generatorConfig.xml"); 
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    } 
    
    public static void main(String[] args) throws Exception {
        try {
            GeneratorDisplay generatorSqlmap = new GeneratorDisplay();
            generatorSqlmap.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

這個其實也是調用mybatis generator實現的。跟mybatis generator安裝插件是一樣的。

注意:利用Generator自動生成代碼,對於已經存在的文件會存在覆蓋和在原有文件上追加的可能性,不宜多次生成。如需重新生成,需要刪除已生成的源文件。

 

4、Mybatis Generator自動生成pojo和mapper

運行GeneratorDisplay 如下圖所示,即可自動生成相關的代碼。

 

 

上圖可以看到,pojo 包裏面自動生成了User 實體對象 ,mapper包裏面生成了 UserMapper 和UserSqlProvider 類。UserMapper 是所有方法的實現。UserSqlProvider則是為UserMapper 實現動態SQL。

注意:

  UserMapper 中的所有的動態SQL腳本,都定義在類UserSqlProvider中。若要增加新的動態SQL,只需在UserSqlProvider中增加相應的方法,然後在UserMapper中增加相應的引用即可,

  如:@UpdateProvider(type=UserSqlProvider.class, method=”updateByPrimaryKeySelective”)。

 

 

三、實現增刪改查

在項目中整合了Mybatis並通過自動生成工具生成了相關的mapper和配置文件之後,下面就開始項目中的調用。這個和之前的xml 配置版也是一樣的。

1、在service包下創建UserService及UserServiceImpl接口實現類

創建com.weiz.service包,添加UserService接口類

package com.weiz.service;

import com.weiz.pojo.User;

public interface UserService {
    public int saveUser(User user);
    public int updateUser(User user);
    public int deleteUser(String userId);
    public User queryUserById(String userId);
}

創建com.weiz.service.impl包,並增加UserServiceImpl實現類,並實現增刪改查的功能,由於這個代碼比較簡單,這裏直接給出完整的代碼。

package com.weiz.service.impl;

import com.weiz.mapper.UserMapper;
import com.weiz.pojo.User;
import com.weiz.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public int saveUser(User user) {
        return userMapper.insertSelective(user);
    }

    @Override
    public int updateUser(User user) {
        return userMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    public int deleteUser(String userId) {
        return userMapper.deleteByPrimaryKey(userId);
    }

    @Override
    public User queryUserById(String userId) {
        return userMapper.selectByPrimaryKey(userId);
    }
}

 

2、編寫controller層,增加MybatisController控制器

package com.weiz.controller;

import com.weiz.pojo.User;
import com.weiz.utils.JSONResult;
import com.weiz.service.UserService;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@RequestMapping("mybatis")
public class MyBatisCRUDController {

    @Autowired
    private UserService userService;

    @Autowired
    private Sid sid;

    @RequestMapping("/saveUser")
    public JSONResult saveUser() {

        String userId = sid.nextShort();
        User user = new User();
        user.setId(userId);
        user.setUsername("spring boot" + new Date());
        user.setNickname("spring boot" + new Date());
        user.setPassword("abc123");
        user.setIsDelete(0);
        user.setRegistTime(new Date());

        userService.saveUser(user);
        return JSONResult.ok("保存成功");
    }

    @RequestMapping("/updateUser")
    public JSONResult updateUser() {
        User user = new User();
        user.setId("10011001");
        user.setUsername("10011001-updated" + new Date());
        user.setNickname("10011001-updated" + new Date());
        user.setPassword("10011001-updated");
        user.setIsDelete(0);
        user.setRegistTime(new Date());

        userService.updateUser(user);
        return JSONResult.ok("保存成功");
    }


    @RequestMapping("/deleteUser")
    public JSONResult deleteUser(String userId) {
        userService.deleteUser(userId);
        return JSONResult.ok("刪除成功");
    }

    @RequestMapping("/queryUserById")
    public JSONResult queryUserById(String userId) {
        return JSONResult.ok(userService.queryUserById(userId));
    }
}

 

3、測試

在瀏覽器輸入controller裏面定義的路徑即可。只要你按照上面的步驟一步一步來,基本上就沒問題,是不是特別簡單。

 

 

最後

以上,就把Spring Boot整合Mybatis註釋版 實現增刪改查介紹完了,Spring Boot 整合Mybatis 是整個Spring Boot 非常重要的功能,也是非常核心的基礎功能,希望大家能夠熟練掌握。後面會深入介紹Spring Boot的各個功能和用法。

這個系列課程的完整源碼,也會提供給大家。大家關注我的微信公眾號(架構師精進),回復:springboot源碼。獲取這個系列課程的完整源碼。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

【大廠面試08期】談一談你對HashMap的理解?

摘要

HashMap的原理也是大廠面試中經常會涉及的問題,同時也是工作中常用到的Java容器,本文主要通過對以下問題進行分析講解,來幫助大家理解HashMap的原理。

1.HashMap添加一個鍵值對的過程是怎麼樣的?

2.為什麼說HashMap不是線程安全的?

3.為什麼要一起重寫hashCode()和equal()方法?

HashMap添加一個鍵值對的過程是怎麼樣的?

這是網上找的一張流程圖,可以結合著步驟來看這個流程圖,了解添加鍵值對的過程。

1.初始化table

判斷table是否為空或為null,否則執行resize()方法(resize方法一般是擴容時調用,也可以調用來初始化table)。

2.計算hash值

根據鍵值key計算hash值。(因為hashCode是一個int類型的變量,是4字節,32位,所以這裡會將hashCode的低16位與高16位進行一個異或運算,來保留高位的特徵,以便於得到的hash值更加均勻分佈)

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

3.插入或更新節點

根據(n – 1) & hash計算得到插入的數組下標i,然後進行判斷

table[i]==null

那麼說明當前數組下標下,沒有hash衝突的元素,直接新建節點添加。

table[i].hash == hash &&(table[i]== key || (key != null && key.equals(table[i].key)))

判斷table[i]的首個元素是否和key一樣,如果相同直接更新value。

table[i] instanceof TreeNode

判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹,如果是紅黑樹,則直接在樹中插入鍵值對。

其他情況

上面的判斷條件都不滿足,說明table[i]存儲的是一個鏈表,那麼遍歷鏈表,判斷是否存在已有元素的key與插入鍵值對的key相等,如果是,那麼更新value,如果沒有,那麼在鏈表末尾插入一個新節點。插入之後判斷鏈表長度是否大於8,大於8的話把鏈錶轉換為紅黑樹。

4.擴容

插入成功后,判斷實際存在的鍵值對數量size是否超多了最大容量threshold(一般是數組長度*負載因子0.75),如果超過,進行擴容。

源代碼如下:

2.為什麼說HashMap不是線程安全的?

其實通過學習HashMap添加鍵值對的方法,我們可以看到整個方法內都沒有使用到鎖,所以一旦多線併發訪問,就有可能造成數據不一致的問題,

例如:

如果有兩個添加鍵值對的線程都執行到if ((tab = table) == null || (n = tab.length) == 0)這行語句,都對table變量進行數組初始化,就會造成已經初始化好的數組table被覆蓋,然後前面初始化的線程會將鍵值對添加到之前初始化的數組中去,造成鍵值對丟失。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    // tab為空則創建 
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    ...後面的代碼省略
}

3.為什麼要一起重寫hashCode()和equal()方法?

當我們的對象一旦作為HashMap中的key,或者是HashSet中的元素使用時,就必須同時重寫hashCode()和equal()方法

首先看看hashCode()和equal()方法的默認實現

可以看到Obejct類中的源碼如下,可以看到equals()方法的默認實現是判斷兩個對象的內存地址是否相同來決定返回結果。

    public native int hashCode();
	public boolean equals(Object obj) {
        return (this == obj);
    }

網上很多博客說hashCode的默認實現是返回內存地址,其實不對,以OpenJDK為例,hashCode的默認計算方法有5種,有返回隨機數的,有返回內存地址,具體採用哪一種計算方法取決於運行時庫和JVM的具體實現。

感興趣的朋友可以看看這篇博客
https://blog.csdn.net/xusiwei1236/article/details/45152201

然後看看hashCode()方法,equal()方法在HashMap中的應用

static final int hash(Object key) {
    int h;
    //因為hashCode是一個int類型的變量,是4字節,32位,所以這裡會將hashCode的低16位與高16位進行一個異或運算,來保留高位的特徵,以便於得到的hash值更加均勻分佈
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

為了將一組鍵值對均勻得存儲在一個數組中,HashMap對key的hashCode進行計算得到一個hash值,用hash對數組長度取模,得到數組下標,將鍵值對存儲在數組下標對應的鏈表下(假設鏈表長度小於8,沒有達到轉換為紅黑樹的閥值)。

下面是添加鍵值對的putVal()方法,當數組下標對應的是一個鏈表時執行的代碼

//遍歷鏈表
for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {//已經遍歷到鏈表末尾,說明鏈表不存在這個key
        p.next = newNode(hash, key, value, null);//在末尾添加這個鍵值對
        if (binCount >= TREEIFY_THRESHOLD - 1) //超過鏈錶轉化為紅黑樹的閥值(也急速鏈表長度》=8)
            treeifyBin(tab, hash);
        break;
    }
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        break;
    p = e;
}

可以清楚地看到判斷添加的key與鏈表中已存在的key是否相等的方法主要是e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))),
也就是:
1.先判斷hash值是否相等,不相等直接結束判斷,因為hash值不相等,key肯定不相等。
2.判斷兩個key對象的內存地址是否相等(相等指向內存中同一個對象)。
3.key不為null,調用key的equal()方法判斷是否相等,因為有可能兩個key在內存中存儲的地址不一樣,但是是相等的。
就像是

String a = new String("test");
String b = new String("test");

System.out.println("a==b is "+a==b);//打印為false
System.out.println("a.equals(b) is "+a.equals(b));//打印為true

背景

假設我們有一個KeyObject類,假設我們認為兩個KeyObject的屬性a相等,那麼KeyObject就是相等的相等的,我們將KeyObject作為HashMap的key,以KeyObject是否相等作為去重標準,不能重複添加KeyObject相等,value不等的值到HashMap中去

public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }
}

假設都hashCode()方法和equals()方法都不重寫(結果:HashMap無法保證去重)

執行以下代碼:

public static void main(String[] args) {
    KeyObject key1 = new KeyObject(1);
    KeyObject key2 = new KeyObject(1);
    System.out.println("key1的hashCode為"+ key1.hashCode());
    System.out.println("key2的hashCode為" + key2.hashCode());
    System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
    HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
    hashMap.put(key1,"value1");
    hashMap.put(key2,"value2");
    //打印hashMap
    for(KeyObject key :hashMap.keySet()){
        System.out.println("KeyObject.a="+key.a+" : "+hashMap.get(key));
    }
}

如果KeyObject的hashCode()方法和equals()方法都不重寫,那麼即便KeyObject的屬性a都是1,key1和key2的hashCode都是不相同的,key1和key2調用equals()方法也不相等,這樣hashMap中就可以同時存在key1和key2了。

打印結果:

key1的hashCode為728890494
key2的hashCode為1558600329
key1.equals(key2)的結果為false
KeyObject.a=1 : value1
KeyObject.a=1 : value2

假如只重寫hashCode()方法(結果:無法正確地與鏈表元素進行相等判斷,從而無法保證去重)

執行以下代碼:

 public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }

    @Override
    public int hashCode() {
        return a;
    }

    public static void main(String[] args) {
        KeyObject key1 = new KeyObject(1);
        KeyObject key2 = new KeyObject(1);
        System.out.println("key1的hashCode為"+ key1.hashCode());
        System.out.println("key2的hashCode為" + key2.hashCode());
        System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
        HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
        hashMap.put(key1,"value1");
        hashMap.put(key2,"value2");
        for(KeyObject key :hashMap.keySet()){
            System.out.println("TestObject.a="+key.a+" : "+hashMap.get(key));
        }
    }
}

此時equal()方法的實現是默認實現,也就是當兩個對象的內存地址相等時,equal()方法才返回true,雖然key1和key2的a屬性是相同的,但是他們在內存中是不同的對象,所以key1==key2結果會是false,KeyObject的equals()方法默認實現是判斷兩個對象的內存地址,所以 key1.equals(key2)也會是false,所以這兩個鍵值對可以重複地添加到hashMap中去。

輸出結果:

key1的hashCode為1
key2的hashCode為1
key1.equals(key2)的結果為false
TestObject.a=1 : value1
TestObject.a=1 : value2

假如只重寫equals()方法(結果:映射到HashMap中不同數組下標,無法保證去重)

public static class KeyObject {
    Integer a;
    public KeyObject(Integer a) {
        this.a = a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        KeyObject keyObject = (KeyObject) o;
        return Objects.equals(a, keyObject.a);
    }

    public static void main(String[] args) {
        KeyObject key1 = new KeyObject(1);
        KeyObject key2 = new KeyObject(1);
        System.out.println("key1的hashCode為"+ key1.hashCode());
        System.out.println("key2的hashCode為" + key2.hashCode());
        System.out.println("key1.equals(key2)的結果為"+(key1.equals(key2)));
        HashMap<KeyObject,String> hashMap = new HashMap<KeyObject,String>();
        hashMap.put(key1,"value1");
        hashMap.put(key2,"value2");
        for(KeyObject key :hashMap.keySet()){
            System.out.println("TestObject.a="+key.a+" : "+hashMap.get(key));
        }
    }
}

假設只equals()方法,hashCode方法會是默認實現,具體的計算方法取決於JVM,(測試時發現是內存地址不同但是相等的對象,它們的hashCode不相同),所以計算得到的數組下標不相同,會存儲到hashMap中不同數組下標下的鏈表中,也會導致HashMap中存在重複元素。

輸出結果如下:

key1的hashCode為1289479439
key2的hashCode為6738746
key1.equals(key2)的結果為true
TestObject.a=1 : value1
TestObject.a=1 : value2

總結

所以當我們的對象一旦作為HashMap中的key,或者是HashSet中的元素使用時,就必須同時重寫hashCode()和equal()方法,因為hashCode會影響key存儲的數組下標及與鏈表元素的初步判斷,equal()是作為判斷key與鏈表中的key是否相等的最後標準。

  • 所以只重寫hashCode()方法,會導致無法正確地與鏈表元素進行相等判斷,從而無法保證去重)
  • 只重寫equals()方法導致鍵值對映射到HashMap中不同數組下標,無法保證去重

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

防海水高溫傷核反應爐 瑞典要求核電廠提計畫

摘錄自2018年8月21日中央社報導

瑞典核能監管機關瑞典輻射安全局局長培爾松20日表示,為防範海水高溫傷害核反應爐,他們已要求國內核電廠營運商近月內提出因應計畫。

今夏熱浪造成瑞典7月氣溫攀升至歷史新高,用來冷卻核反應爐的海水溫度也因此遠高於正常水準,並超過安全標準,導致瑞典數個核電廠反應爐必須關閉或減少發電量。

上回瑞典輻射安全局(Swedish Radiation Safety Authority, SSM)要求核電廠提出反應爐修改計畫,是在2011年日本發生福島核災之後。當時提出截至2020年的修改計畫,所需經費達數億歐元。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

研究:為挽救蜜蜂的二代農藥「速殺氟」會扼殺熊蜂後代

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

澳洲政府修能源政策 溫室氣體減排以後再談

摘錄自2018年8月21日中央廣播電台報導

路透社報導,在執政聯盟內部的反對下,澳洲總理滕博爾(Malcolm Turnbull)今天(20日)取消能源政策中要求減少排放溫室氣體的部分。但他表示,澳洲仍信守巴黎氣候協議(Paris Agreement)承諾。

滕博爾政府的能源政策「國家能源保障」(National Energy Guarantee),先前要求發電產業的溫室氣體排放量,到2030年以前,必須比2005年減少26%。

墨爾本大學(University of Melbourne)政治學教授艾克斯利(Robyn Eckersley)則說:「這完全是對澳洲自由黨(Liberal Party)
右翼成員投降,他們希望永久保留澳洲的煤礦經濟。」

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

通用汽車關廠效應!白宮:將取消電動車、再生能源補貼

通用汽車(General Motors Co.,GM)上週決定關閉美國工廠、裁減員工,並把焦點轉向電動車,引發美國總統川普(Donald Turmp)怒火,也堅定了川普政府終結電動車、再生能源補貼的決心。白宮國家經濟委員會會長庫卓(Larry Kudlow)透露,歐巴馬時期的補貼政策將在 2020 年或 2021 年全面終止。

路透社、The Hill、Mashable 等外電報導,庫卓 3 日在被問到 GM 關廠裁員的行動時,提到美國消費者購買插電式電動車時、都可獲得 2,500~7,500 美元的稅收抵免優惠,當中也包括 GM 製造的車種。

庫卓說,白宮希望終結電動車及其他歐巴馬執政時推出的補貼政策,當中也會包括可再生能源,預計終止的時間大概會落於 2020 年或 2021 年。

根據國會規定,每家製造商只能為 20 萬輛汽車提供稅收抵免優惠,在超過上限後,補貼就會逐步減少。GM 預測該公司 2018 年底就會達到門檻,依據當前聯邦法令的規定,這代表 GM 的汽車抵稅優惠方案將在 2020 年告終。

特斯拉今年 7 月就已宣布抵達 20 萬輛汽車的門檻。其他汽車製造商則還要花上幾年才會觸及。

川普上週威脅要剔除 GM 申請電動車抵稅優惠補貼的資格,以報復該公司關廠裁員的決定。不過,專家直指,白宮無法單方面修改電動車抵稅優惠的法令。

聯合國(UN)最近才剛發布評估報告,直指氣候變遷恐對環境帶來嚴重危害,呼籲政府直接介入、避免災難爆發。不過,白宮認為此份報告太過誇張。美國甫於 7 月退出巴黎協議。

…..and G.M. would not be closing their plants in Ohio, Michigan & Maryland. Get smart Congress. Also, the countries that send us cars have taken advantage of the U.S. for decades. The President has great power on this issue – Because of the G.M. event, it is being studied now!

— Donald J. Trump (@realDonaldTrump)

(本文內容由 授權使用。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

低碳趨勢無法擋,石油巨擘殼牌進軍歐洲EV充電市場

 

荷蘭皇家殼牌(Royal Dutch Shell plc)10月12日宣布收購電動車(EV)充電服務經營商NewMotion。依據收購條件、NewMotion將成為殼牌旗下全資子公司。

殼牌新聞稿顯示,NewMotion在英國、法國、德國以及荷蘭經營超過3萬個私人(包括家庭、企業)電動車充電點。此外,NewMotion在歐洲25個國家擁有超過5萬個公共充電點、對逾10萬張註冊充電卡提供服務。

NewMotion表示,這項收購案將可協助公司提升EV充電服務、將更多的停車空間改裝成充電站,進而提升歐洲使用者的充電體驗。

(本文內容由授權使用。圖片出處:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

中國挺氫燃料電池發展,2020年氫能產業料迎爆發期

  經濟參考報報導,中國產自佛山(雲浮)產業轉移工業園的氫能燃料電池汽車,在今年《北京國際風能與中國太陽能大會暨展覽會》上,吸引眾多人的圍觀。在展期間舉行的「氫產業•氫生活•氫未來」主題新聞發布會上,業內人士認為,氫能早已過了概念性的階段,預計三到五年時間內,氫能產業即會進入爆發期。   中國科技部部長萬鋼日前在第十九屆中國科協年會上也表示,氫具來源廣泛、大規模穩定儲存、持續供應、遠距離運輸以及快速補充等特點,在未來車用能源中,氫燃料與電力將並存互補,共同支撐新能源汽車產業發展;且必須加強協同創新,加快推動氫能燃料電池產業全面發展。   目前,中國各地也都在積極推動燃料電池發展。今年9月上海發布《上海市燃料電池汽車發展規畫》,規劃到2020年,上海將會聚集超過100家燃料電池汽車相關企業,於2025年建成50座加氫站,到2030年實現燃料電池汽車技術和製造整體達到海外同等水準,上海燃料電池汽車全產業鏈年產值突破3,000億元人民幣。   而上述來自佛山產業轉移工業園的氫能燃料電池汽車,則包含氫能乘用車、氫燃料電池城市客車以及燃料電池物流車等多款車型。同時,2016年5月,廣東國鴻氫能科技與加拿大巴拉德簽署引進9SSL電堆生產線技術協定,在中國建設年生產兩萬台電堆和5,000套系統的首條商業化燃料電池電堆及系統整合生產線,該項目已於今年7月1日正式投產,首批試製電堆樣品主要性能指標達到國際先進水準,計畫今年生產3000台9SSL電堆,系統整合1,000套。   佛山市委常委許國也認為,現在氫能產業發展最大的障礙不是技術而是基礎設施建設。不過,預計後續加氫站的建設在中國會取得突飛猛進的效果,中國央企尤其是中石化正在對中國的加油站合建加氫站的問題進行全面布局。   中國全國氫能標準技術委員會高級顧問陳霖新認為,氫能早已過了概念性的階段,現在要進入踏踏實實發展的階段。許國則判斷,中國國家政策還是以示範為主,未來產業技術好的區域自然能搶佔先機,取得更多的市場份額,預計在未來三到五年時間內,即2020年左右,氫能產業會取得突飛猛進的發展,而這個爆發點只會提前不會推遲。   (本文內容由授權使用。首圖來源:by pixelfreestyle via Flickr CC2.0)      

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準