遏制空污 新德里裝空污預警系統

摘錄自2018年10月2日中央社新德里報導

印度新德里空氣污染嚴重程度經常位居世界前幾名,新德里高層官員表示,2018年在進入空污嚴重的冬天前,空污預警系統即將啟用,預計在10月底或11月初安裝,可預測兩天後的空氣品質,以提前遏制空污。

空污系統安裝好後,將從印度中央污染控制局(Central Pollution Control Board,CPCB)、德里污染控制委員會(Delhi Pollution Control Committee)和空氣品質及天氣預測與研究系統機構(System of Air Quality & Weather Forecasting and Research,SAFAR)旗下的36個空氣品質監測站獲得數據,同時從美國國家航空暨太空總署(NASA)衛星獲取即時氣候資料,綜合研判後,對空氣品質進行預測。

協助這項預警系統設置的印度熱帶研究所普恩分所(Indian Institute of Tropical Meteorology-Pune)科學家谷德表示,系統安裝後的第一年,僅空污濃度指標PM2.5(細懸浮微粒)數據被輸入系統,未來幾年將把PM10、二氧化硫(SO2)、二氧化氮(NO2)濃度等數據都納入系統,使空污預測更加準確。

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

Python多線程與隊列

Python多線程與Queue隊列多線程在感官上類似於同時執行多個程序,雖然由於GIL的存在,在Python中無法實現線程的真正并行,但是對於某些場景,多線程仍不失為一個有效的處理方法:

1,不緊急的,無需阻塞主線程的任務,此時可以利用多線程在後台慢慢處理;
2,IO密集型操作,比如文件讀寫、用戶輸入和網絡請求等,此時多線程可以近似達到甚至優於多進程的表現;

多線程的基本使用不再贅述,以下語法便可輕鬆實現:

1 def task(args1, args2):
2     pass
3 
4 Thread(
5     target=task,
6     args=(args1, args2)
7 ).start()

這裏我們重點關注線程通信。

假設有這麼一種場景:有一批源數據,指定一個操作係數N,需要分別對其進行與N的加減乘除操作,並將結果匯總。
當然這裏的加減乘除只是一種簡單處理,在實際的生產環境中,它其實代表了一步較為複雜的業務操作,並包含了較多的IO處理。

自然我們想到可以開啟多線程處理,那麼緊接着的問題便是:如何劃分線程,是根據處理步驟劃分,還是根據源數據劃分?

對於前者,我們把涉及的業務操作單獨劃分位一個線程,即有4個線程分別進行加減乘除的操作,顯然上一個線程的結果是下一個線程的輸入,這類似於流水線操作;

而後者則是把源數據分為若干份,每份啟動一個線程進行處理,最終把結果匯總。一般來說,我們推薦第一種方式。因為在一個線程中完成所有的操作不如每步一個線程清晰明了,

尤其是在一些複雜的場景下,會加大單個線程的出錯概率和測試難度。

那麼我們將開闢4個線程,分別執行加減乘除操作。最後一個除法線程結束則任務完成:

 

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from Queue import Queue
 5 from threading import Thread
 6 
 7 
 8 class NumberHandler(object):
 9     def __init__(self, n):
10         self.n = n
11 
12     def add(self, num):
13         return num + self.n
14 
15     def subtract(self, num):
16         return num - self.n
17 
18     def multiply(self, num):
19         return num * self.n * self.n
20 
21     def divide(self, num):
22         return num / self.n
23 
24 
25 class ClosableQueue(Queue):
26     SENTINEL = object()
27 
28     def close(self):
29         self.put(self.SENTINEL)
30 
31     def __iter__(self):
32         while True:
33             item = self.get()
34             try:
35                 if item is self.SENTINEL:
36                     return
37                 yield item
38             finally:
39                 self.task_done()
40 
41 
42 class StoppableWorker(Thread):
43     def __init__(self, func, in_queue, out_queue):
44         super(StoppableWorker, self).__init__()
45         self.in_queue = in_queue
46         self.out_queue = out_queue
47         self.func = func
48 
49     def run(self):
50         for item in self.in_queue:
51             result = self.func(item)
52             self.out_queue.put(result)
53             print self.func
54 
55 
56 if __name__ == '__main__':
57     source_queue = ClosableQueue()
58     add_queue = ClosableQueue()
59     subtract_queue = ClosableQueue()
60     multiply_queue = ClosableQueue()
61     divide_queue = ClosableQueue()
62     result_queue = ClosableQueue()
63 
64     number_handler = NumberHandler(5)
65 
66     threads = [
67         StoppableWorker(number_handler.add, add_queue, subtract_queue),
68         StoppableWorker(number_handler.subtract, subtract_queue, multiply_queue),
69         StoppableWorker(number_handler.multiply, multiply_queue, divide_queue),
70         StoppableWorker(number_handler.divide, divide_queue, result_queue),
71     ]
72 
73     for _thread in threads:
74         _thread.start()
75 
76     for i in range(10):
77         add_queue.put(i)
78 
79     add_queue.close()
80     add_queue.join()
81     print 'add job done...'
82     subtract_queue.close()
83     subtract_queue.join()
84     print 'subtract job done...'
85     multiply_queue.close()
86     multiply_queue.join()
87     print 'multiply job done...'
88     divide_queue.close()
89     divide_queue.join()
90     print 'divide job done...'
91     result_queue.close()
92 
93     print "%s items finished, result: %s" % (result_queue.qsize(), result_queue)
94 
95     for i in result_queue:
96         print i

運行結果:

線程執行日誌:

 

 

 總的結果:

 

 可見線程交叉運行,但是任務卻是順序結束,這符合我們的預期。

值得注意的是,我們在ClosableQueue定義了一個close()方法,通過放入一個特殊的類變量SENTINEL告訴隊列應該關閉。此外,由於直接加減乘除結果不變,因此我特意乘了兩次來便於我們判斷結果。

總結:

1. Queue是一種高效的任務處理方式,它可以把任務處理流程劃分為若干階段,並使用多條python線程來同時執行這些子任務;

2. Queue類具備阻塞式的隊列操作、能夠指定緩衝區尺寸,而且還支 持join方法,這使得開發者可以構建出健壯的流水線。

 

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

java property 配置文件管理工具框架,避免寫入 property 亂序

property

是 java 實現的 property 框架。

特點

  • 優雅地進行屬性文件的讀取和更新

  • 寫入屬性文件后屬性不亂序

  • 靈活定義編碼信息

  • 使用 OO 的方式操作 property 文件

  • 支持多級對象引用

變更日誌

快速開始

環境依賴

Maven 3.x

Jdk 1.7+

Maven 引入依賴

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>property</artifactId>
    <version>0.0.4</version>
</dependency>

入門案例

讀取屬性

PropertyBs.getInstance("read.properties").get("hello");

read.properties 為文件路徑,hello 為存在的屬性值名稱。

讀取屬性指定默認值

final String value = PropertyBs.getInstance("read.properties")
                .getOrDefault("hello2", "default");

read.properties 為文件路徑,hello2 為不存在的屬性值名稱,default 為屬性不存在時返回的默認值。

設置屬性

PropertyBs.getInstance("writeAndFlush.properties").setAndFlush("hello", "world-set");

writeAndFlush.properties 為文件路徑,hello 為需要設置的屬性信息。

引導類方法概覽

序號 方法 說明
1 getInstance(propertyPath) 獲取指定屬性文件路徑的引導類實例
2 charset(charset) 指定文件編碼,默認為 UTF-8
3 get(key) 獲取 key 對應的屬性值
4 getOrDefault(key, defaultValue) 獲取 key 對應的屬性值,不存在則返回 defaultValue
5 set(key, value) 設置值(內存)
6 remove(key) 移除值(內存)
7 flush() 刷新內存變更到當前文件磁盤
9 flush(path) 刷新內存變更到指定文件磁盤
10 set(map) 設置 map 信息到內存
11 set(bean) 設置 bean 對象信息到內存
12 asMap() 返回內存中屬性信息,作為 Map 返回
13 asBean(bean) 返回內存中屬性信息到 bean 對象中

對象

簡介

我們希望操作 property 可以想操作對象一樣符合 OO 的思想。

設置值

User user = new User();
user.setName("hello");
user.setHobby("hobby");

final long time = 1574147668411L;
user.setBirthday(new Date(time));

PropertyBs propertyBs = PropertyBs.getInstance("setBean.properties")
        .set(user);

Assert.assertEquals("hobby", propertyBs.get("myHobby"));
Assert.assertEquals("1574147668411", propertyBs.get("birthday"));

讀取值

PropertyBs propertyBs = PropertyBs.getInstance("setBean.properties"
        .set("myHobby", "play")
        .set("birthday", "1574147668411");
User user = new User();
propertyBs.asBean(user);
Assert.assertEquals("play", user.getHobby());
Assert.assertEquals(1574147668411L, user.getBirthday().getTime());

對象定義

  • User.java
public class User {

    private String name;

    @PropertyField("myHobby")
    private String hobby;

    @PropertyField(converter = DateValueConverter.class)
    private Date birthday;

}

@PropertyField 註解

序號 屬性 默認值 說明
1 value 當前字段名稱 對應的 property 屬性名稱
2 converter 默認轉換實現 DefaultValueConverter 對當前字段進行屬性的轉換處理

自定義轉換類

  • DateValueConverter.java

這個就是我們針對 Date 類型,自己實現的處理類型。

實現如下:

public class DateValueConverter implements IValueConverter {

    @Override
    public Object fieldValue(String value, IFieldValueContext context) {
        return new Date(Long.parseLong(value));
    }

    @Override
    public String propertyValue(Object value, IPropertyValueContext context) {
        Date date = (Date)value;
        return date.getTime()+"";
    }

}

集合

說明

有時候一個屬性可能是集合或者數組,這裏暫時給出比較簡單的實現。

將字段值直接根據逗號分隔,作為屬性值。

測試案例

UserArrayCollection userArrayCollection = buildUser();
PropertyBs propertyBs = PropertyBs.getInstance("setBeanArrayCollection.properties")
        .set(userArrayCollection);
Assert.assertEquals("array,collection", propertyBs.get("alias"));
Assert.assertEquals("array,collection", propertyBs.get("hobbies"));

對象定義

  • UserArrayCollection.java
public class UserArrayCollection {

    private List<String> alias;

    private String[] hobbies;
}

暫時只支持 String 類型,不想做的過於複雜。

後期將考慮添加各種類型的支持。

多級對象

說明

有時候我們在一個對象中會引用其他對象,比如 對象 a 中包含對象 b。

這裏採用 a.b.c 這種方式作為屬性的 key, 更加符合使用的習慣。

測試案例

設置

Book book = new Book();
book.name("《海底兩萬里》").price("12.34");
UserEntry user = new UserEntry();
user.name("海倫").book(book).age("10");
PropertyBs propertyBs = PropertyBs.getInstance("setBeanEntry.properties")
        .set(user);
Assert.assertEquals("海倫", propertyBs.get("name"));
Assert.assertEquals("10", propertyBs.get("age"));
Assert.assertEquals("《海底兩萬里》", propertyBs.get("book.name"));
Assert.assertEquals("12.34", propertyBs.get("book.price"));

讀取

Map<String, String> map = new HashMap<>();
map.put("name", "海倫");
map.put("age", "10");
map.put("book.name", "《海底兩萬里》");
map.put("book.price", "12.34");
UserEntry userEntry = new UserEntry();
PropertyBs.getInstance("setBeanEntry.properties")
        .set(map)
        .asBean(userEntry);
Assert.assertEquals("UserEntry{name='海倫', age=10, book=Book{name='《海底兩萬里》', price=12.34}}",
        userEntry.toString());

對象定義

  • UserEntry.java
public class UserEntry {

    private String name;

    private String age;

    @PropertyEntry
    private Book book;

}
  • Book.java
public class Book {

    private String name;

    private String price;

}

@PropertyEntry 說明

@PropertyEntry 註解用來標識一個字段是否採用多級對象的方式表示。

這個註解只有一個屬性,就是 value(),可以用來給當前字段指定一個別稱,和 @PropertyField 別稱類似。

後續特性

  • 提供更多內置的類型轉換實現

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

打破松下壟斷,特斯拉擬向Samsung SDI採購車用電池

美商特斯拉(Tesla)所生產的電動車所使用之車用蓄電池,至目前仍幾乎都由日本松下(Panasonic)供應,幾乎形成壟斷狀況。日媒報導,特斯拉計畫拓展電池採購對象,目前已與韓商Samsung SDI展開最終協調。

《日經中文網》一篇報導指出,特斯拉為供應需求日漸成長的純電動車所需的蓄電池,計畫推行多樣化採購對象,且與Samsung SDI的合作,目前已到了最終階段。據報導,Samsung SDI的純電動車用鋰電池已送至位於美國加州的特斯拉開發基地,但由於數量較大,因此被認為已到了正式採用前的試驗階段,而非產品試驗用品。

松下所供應的電動車用蓄電池在質、量兩方面一直占有市場優勢,因此佔據電動車市場供應的大宗。松下與特斯拉於2015年在美國內華達州展開的Gigafactory建設計畫仍在持續,且有部分產能陸續投產,預計將在今年七月底初步完工。

Gigafactory原先規劃的產能為2020年時50GWh,但由於特斯拉還發表了儲能設備Powerpack 和Powerwall ,且市場對Tesla Model 3的反應熱烈,使特斯拉客戶對鋰電池的需求大增,因此有擴增Gigafactory產量的計畫。

而目前供應純電動車用鋰電池的廠商,除了松下、Samsung SDI之外,另一主要廠商為韓國LG Chem,但供應量不大。

(照片來源:Samsung SDI)

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

三星、LG未獲中國電動車用電池認證

韓國三星SDI、LG Chem兩大電池廠商申請中國電動車用鋰電池認證,但遭拒於門外,意味車用電池在中國銷售時無法獲得補貼,幾乎等同遭市場排擠。兩者均表示將在年內重提申請。

根據《東網》與《MoneyDJ》等媒體之相關報導,三星SDI、LG Chem與其他31家中國電池廠商共同向中國公信部提交電動汽車電池認證,但除了兩家韓廠外,其他廠商均名列20日公布的《汽車動力蓄電池行業規範條件》企業目錄名單。

中國已公告,2018年1月開始,只有配備工信部認證電池的車輛才可獲得電動車採購補貼。由於補貼金佔電動車價格達40%,無補貼的電池很難找到客戶,幾乎等於被排擠於市場之外。

三星SDI、LG Chem均表示不清楚被拒原因,且都將於今年重新遞交申請。

中國電動車競爭日漸激烈,政府也曾祭出保護本土產業的措施,包括要求成品須有一定比例零件於本地生產等。但這次三星SDI、LG Chem踢到鐵板,引發保護政策的疑慮,韓廠憂心中國政府將祭出更嚴密的保護措施。不過,兩家公司已分別在中國南京與西安建立電池工廠,投產後疑慮可望降低。

三星SDI與LG Chem目前共供應全球約1/3電動車用電池,因看好中國市場發展性而積極搶進。LG Chem現有客戶包括通用汽車、福特(Ford)與現代,中國客戶有上汽集團與奇瑞汽車。三星SDI則有鄭州宇通、北汽福田兩家中國客戶,且之前傳出將為特斯拉供應電池產品,但特斯拉已表示Model 3仍將獨家採用Panasonic的電池。

(照片來源:shared by CC 2.0 )

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

台灣特斯拉售價公布,Model S台幣306萬元起跳

特斯拉的台灣櫃點曝光,官網上也更新了台灣車款訊息以及價格。經典車款Model S最低價約為新台幣306.1萬元,而Model X與Model 3的價格則仍待公布。台灣使用者也可購買Powerwall產品。

根據台灣特斯拉所揭露的訊息,Model S車款共分成:60(60kWh電池、後輪驅動)、75(75kWh電池、後輪驅動)、90D(90kWh電池、全時四輪驅動)以及P90D(90kWh Performance電池、全時四輪驅動)等四款,含稅、不含政府補貼的現金售價由新台幣306.1萬元起跳,最昂貴的P90D現金價為502萬元。車主亦可加價選配Autopilot輔助駕駛功能、Ultra Hi-Fi音響等配備。

車款的配備與續航力等訊息也在網站上公開,續航力最佳的90D可行駛557公里。而特斯拉也同步公開油費與牌照稅的節省訊息,Model S每款車輛在五年的行駛當中,平均可節省新台幣6.7萬元。

備受矚目的平價車款Model 3台灣定價預計在2017年公布,有興趣的車主現可支付3.3萬元預購,車輛將在2017年下半年從美國開始陸續交車。若比對Model S 60的美國版定價6.6萬元美金,美國定價3.5萬美金的Model 3,台灣版定價可能會超過新台幣150萬。

台灣客戶可開始在台灣特斯拉官網上預購「能源牆」儲能電池。(來源:Tesla Taiwan)

此外,特斯拉亦將開始在台灣布建超級充電站,主要將設置於主幹道、人口密集區或特定商業場所。台灣使用者也可開始預購儲能系統6.4kWh版的Powerwall(正式定名「能源牆」),以供家庭或搭配電動車使用,亦可整合太陽能板。

(首圖:台灣特斯拉官網 Model S 車款介紹。翻攝台灣特斯拉官網)

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

彰化縣祭出電動機車補助,加速改善空氣品質

彰化縣長年受空污所苦,縣府為改善空氣品質,祭出最高新台幣1.9萬元的電動機車購車補助,希望能加速淘汰縣內2.5萬輛老舊機車改用電動車,以減輕空污排放。

彰化縣環保局統計,縣內目前領牌機車共有81.4萬輛,其中有約24.9萬輛是出廠超過12年的二行程老車,空污影響相當大。環保局為減輕PM2.5排放,推出多項補貼措施,目標在今年汰換2.5萬輛老車改用電動車。若能完成目標,每年可減少13公噸PM2.5排放,對縣內空氣環境改善大有助益。

縣府推出的補貼措施依照汰換產品與新購置的電動機車有所不同。汰換二行程機車補貼新台幣1,500元,汰換舊車後新購機車,小型與輕型再補助16,300元、換購重型電動機車則補助19,100元,相當於新車價格的三分之一。

今年前半年,彰化民眾已汰換12,806輛二行程機車,民眾反映普遍良好。但也有民眾希望政府進一步補助電池更換的費用。

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

【其他文章推薦】

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

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

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

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

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

類加載器 – 類的加載、連接與初始化

類的加載、連接與初始化

概述

在Java代碼中,類型的加載、連接與初始化過程都是在程序運行期間完成的

  • 類型:可以理解為一個class
  • 加載:查找並加載類的二進制數據,最常見的情況是將已經編譯完成的類的class文件從磁盤加載到內存中
  • 連接:確定類型與類型之間的關係,對於字節碼的相關處理
    • 驗證:確保被加載的類的正確性
    • 準備:為類的靜態變量分配內存,並將其初始化為默認值。但是在到達初始化之前,類變量都沒有初始化為真正的初始值
    • 解析:在類型的常量池中尋找類、接口、字段和方法的符號引用,把這些符號引用轉換為直接引用的過程
  • 初始化:為類的靜態變量賦予正確的初始值
  • 使用:比如創建對象,調用類的方法等
  • 卸載:類從內存中銷毀

理解:public static int number = 666;

上面這段代碼,在類加載的連接階段,為對象number分配內存,並初始化為0;然後再初始化階段在賦予正確的初始值:666

類的使用方式

Java程序對類的使用方式可分為兩種

  • 主動使用
    • 創建類的實例
    • 訪問某個類或接口的靜態變量,或者對靜態變量賦值
    • 調用類的靜態方法
    • 反射
    • 初始化類的子類
    • Java虛擬機啟動時被標明為啟動類的類(包含main方法)
    • JDK1.7開始提供的動態語言支持(java.lang.invoke.MethodHandle實例的解析結果REF_getStatic,REF_putStatic,REF_invokeStatic句柄對應的類沒有初始化,則初始化)
  • 被動使用
    • 除了主動使用的七種情況之外,其他使用Java類的方法都被看作是對類的被動使用,都不會導致類的初始化

所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才初始化他們

代碼理解

示例一:類的加載連接和初始化過程

代碼一

public class Test01 {
    public static void main(String[] args) {
        System.out.println(Child01.str);
    }
}

class Father01 {
    public static String str = "做一個好人!";
    static {
        System.out.println("Father01 static block");
    }
}

class Child01 extends Father01 {
    static {
        System.out.println("Child01 static block");
    }
}

運行結果做一個好人!

Father01 static block
做一個好人!

代碼二

public class Test01 {
    public static void main(String[] args) {
        System.out.println(Child01.str2);
    }
}

class Father01 {
    public static String str = "做一個好人!";

    static {
        System.out.println("Father01 static block");
    }
}

class Child01 extends Father01 {
    public static String str2 = "做一個好人!";
    static {
        System.out.println("Child01 static block");
    }
}

運行結果

Father01 static block
Child01 static block
做一個好人!

分析:

  • 代碼一中,我們通過子類調用父類中的str,這個str是在父類被定義的,對Father01主動使用,沒有主動使用Child01,故Child01的靜態代碼塊沒有執行,父類的靜態代碼塊被執行了。 -> 對於靜態字段來說,只有直接定義了該字段的類才會被初始化。
  • 代碼二中,對Child01主動使用;根據主動使用的7種情況,調動類的子類時,其所有的父類都會被先初始化,所以Father01會被初始化。 -> 當一個類初始化時,要求其父類全部都已經初始化完畢了。

以上驗證的是類的初始化情況,那麼如何驗證類的加載情況呢,可以通過在啟動的時候配置虛擬機參數:-XX:+TraceClassLoading查看

運行代碼一,查看輸出結果,可以看見控制台打印了very多的日誌,第一個加載的是java.lang.Object類(不管加載哪個類,他的父類一定是Object類),後面是加載的一系列jdk的類,他們都位於rt包下。往下查看,可以看見Loaded classloader.Child01,說明即使沒有初始化Child01,但是程序依然加載了Child01類。

[Opened /usr/local/jdk1.8/jre/lib/rt.jar]
[Loaded java.lang.Object from /usr/local/jdk1.8/jre/lib/rt.jar]
...
[Loaded java.lang.Void from /usr/local/jdk1.8/jre/lib/rt.jar]
[Loaded classloader.Father01 from file:/home/fanxuan/Study/java/jvmStudy/out/production/jvmStudy/]
[Loaded classloader.Child01 from file:/home/fanxuan/Study/java/jvmStudy/out/production/jvmStudy/]
Father01 static block
做一個好人!
[Loaded java.lang.Shutdown from /usr/local/jdk1.8/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /usr/local/jdk1.8/jre/lib/rt.jar]

拓展:JVM參數介紹

因為前一章節使用了JVM參數,所以對其做一下簡單的介紹

  • 所有的JVM參數都是以-XX:開頭的
  • 如果形式是:-XX:+<option>,表示開啟option選項
  • 如果形式是:-XX:-<option>,表示關閉option選項
  • 如果形式是:-XX:<option>=<value>,表示將option選項的值設置為value

示例二:常量的本質含義

public class Test02 {
    public static void main(String[] args) {
        System.out.println(Father02.str);
    }
}

class Father02{
    public static final String str = "做一個好人!";

    static {
        System.out.println("Father02 static block");
    }
}

執行結果

做一個好人!

分析

可以看見,此段代碼並沒有初始化Father02類。這是因為final表示的是一個常量,在編譯階段常量就會被存入到調用這個常量的方法所在的類的常量池當中,本質上,調用類並沒有直接引用到定義常量的類,因此並不會觸發定義常量的類的初始化。在本代碼中,常量str會被存入到Test02的常量池中,之後Test02與Father02沒有任何關係,甚至可以刪除Father02的class文件。

我們反編譯一下Test02類

Compiled from "Test02.java"
public class classloader.Test02 {
  public classloader.Test02();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #4                  // String 做一個好人!
       5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

第一塊是Test02類的構造方法,第二塊是我們要看的main方法。可以看見3: ldc #4 // String 做一個好人!,此時這個值已經是確定無疑的做一個好人!了,而不是Father02.str,證實了上面說的在編譯階段常量就會被存入到調用這個常量的方法所在的類的常量池當中

拓展:助記符

因前一章節涉及到了助記符,所以介紹下本章節涉及到的助記符及擴展

  • ldc:表示將int、float或String類型的常量值常量池中推送至棧頂
  • bipush:表示將單字節(-128 -至 127)的常量推送至棧頂
  • sipush:表示將一個短整形(-32768 至 32767)的常量推送至棧頂
  • iconst_1:表示將int類型的1推送至棧頂(這類助記符只有iconst_m1 – iconst_5七個)

示例三:編譯期常量與運行期常量的區別

public class Test03 {
    public static void main(String[] args) {
        System.out.println(Father03.str);
    }
}

class Father03 {
    public static final String str = UUID.randomUUID().toString();

    static {
        System.out.println("Father03 static block");
    }
}

運行結果

Father03 static block
a60c5db4-2673-4ffc-a9f0-2dbe53fae583

分析

本代碼與示例二的區別在於str的值是在運行時確認的,而不是編譯時就確定好的,屬於運行期常量,而不是編譯期常量。當一個常量的值並非編譯期間確定的,那麼其值就不會被放到調用類的常量池中,這時在程序運行時,會導致主動使用這個常量所在的類,導致這個類被初始化。

示例四:數組創建本質

代碼一

public class Test04 {
    public static void main(String[] args) {
         Father04 father04_1 = new Father04();
        System.out.println("-----------");
        Father04 father04_2 = new Father04();
    }
}

class Father04 {
    static {
        System.out.println("Father04 static block");
    }
}

運行結果

Father04 static block
-----------

分析

  • 創建類的實例時,會初始化類
  • 所有的Java虛擬機實現必須在每個類或接口被Java程序“首次主動使用”時才初始化他們

代碼二

public class Test04 {
    public static void main(String[] args) {
        Father04[] father04s = new Father04[1];
        System.out.println(father04s.getClass());
    }
}

運行結果

class [Lclassloader.Father04;

分析

  • 創建數組對象不再主動使用的7種情況內,屬於被動使用,故不會初始化Father04
  • 打印father04s的類型為[Lclassloader.Father04,這是虛擬機在運行期生成的。 -> 對於數組示例來說,其類型是有JVM在運行期動態生成的,表示為[Lclassloader.Father04這種形式,動態生成的類型,其父類就是Object。
  • 對於數組來說,JavaDoc經常將構成數組的元素為Component,實際上就是將數組降低一個維度后的類型

反編譯一下:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: anewarray     #2                  // class classloader/Father04
       4: astore_1
       5: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       8: aload_1
       9: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      12: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      15: return
  • anewarray:表示創建一個引用類型(如類、接口、數組)的數組,並將其引用值值壓入棧頂
  • newarray:表示創建一個指定的原始類型(如int、float、char等)的數組,並將其引用值壓入棧頂

示例五:接口的加載與初始化

代碼一

public class Test05 {
    public static void main(String[] args) {
        System.out.println(Child05.j);
    }
}

interface Father05 {
    int i = 5;
}

interface Child05 extends Father05 {
    int j = 6;
}

運行結果

6

分析

  • 接口中定義的常量本身就是public、static、final的
  • 結果顯而易見,這時我們刪除掉Father05.class文件和Child05.class文件,程序依然可以正常運行
    • 接口中的常量本身就是final常量,會被加載到Test05的常量池中
    • 此時,Father05和Child05都不會被加載

代碼二

public class Test05 {
    public static void main(String[] args) {
        System.out.println(Child05.j);
    }
}

interface Father05 {
    int i = 5;
}

interface Child05 extends Father05 {
    int j = new Random().nextInt(8);
}

運行結果

6

將Father05.class文件刪除,運行結果

Exception in thread "main" java.lang.NoClassDefFoundError: classloader/Father05
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at classloader.Test05.main(Test05.java:15)
Caused by: java.lang.ClassNotFoundException: classloader.Father05
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 13 more

分析

  • 只有在真正使用到父接口的時候(如引用接口中所定義的常量時),才會加載初始化

代碼三

public class Test05 {
    public static void main(String[] args) {
        System.out.println(Child05.j);
    }
}

interface Father05 {
    Thread thread = new Thread() {
        {
            System.out.println("Father05 code block");
        }
    };
}

class Child05 implements Father05 {
    public static int j = 8;
}

運行結果

8

分析

  • 在初始化一個類時,並不會先初始化他所實現的接口

代碼四

public class Test05 {
    public static void main(String[] args) {
        System.out.println(Father05.thread);
    }
}

interface GrandFather {
    Thread thread = new Thread() {
        {
            System.out.println("GrandFather code block");
        }
    };
}

interface Father05 extends GrandFather{
    Thread thread = new Thread() {
        {
            System.out.println("Father05 code block");
        }
    };
}

運行結果

Father05 code block
Thread[Thread-0,5,main]

分析

  • 在初始化一個接口時,並不會先初始化他的父接口

示例六:類加載器準備階段和初始化階段

代碼一

public class Test06 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();

        System.out.println("i:" + Singleton.i);
        System.out.println("j:" + Singleton.j);
    }
}

class Singleton {
    public static int i;

    public static int j = 0;

    private static Singleton singleton = new Singleton();

    private Singleton() {
        i ++;
        j ++;
    }

    public static Singleton getInstance() {
        return singleton;
    }
}

運行結果

i:1
j:1

分析

首先Singleton.getInstance();進入SingletongetInstance方法,getInstance會返回Singleton的實例,Singleton的實例是new Singleton();出來的,因此調用了自定義的私有構造方法。在調用構造方法之前,給靜態變量賦值,i默認賦值為0,j顯式的賦值為0,經過構造函數之後,值都為1。

代碼二

public class Test06 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();

        System.out.println("i:" + Singleton.i);
        System.out.println("j:" + Singleton.j);
    }
}

class Singleton {
    public static int i;

    private static Singleton singleton = new Singleton();

    private Singleton() {
        i ++;
        j ++;
    }

    public static int j = 0;

    public static Singleton getInstance() {
        return singleton;
    }
}

運行結果

i:1
j:0

分析

程序主動使用了Singleton類,準備階段對類的靜態變量分配內存,賦予默認值,下面給出類在連接及初始化階段常量的值的變化

  • i : 0
  • singleton:null
  • j : 0
  • getInstance:初始化
    • i:0
    • singleton:調用構造函數
      • i:1
      • j:1
    • j:0【覆蓋了之前的1】

故返回的值i為1,j為0

深入解析類的加載、連接與初始化

類的加載

  • 將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後再內存中創建一個java.lang.Class對象(規範並未說明Class對象位於哪裡,HotSpot虛擬機將其放在了方法區中)用來封裝類在方法區的數據結構
  • 加載.class文件的方式
    • 從本地系統直接加載
    • 通過網絡下載.class文件
    • 從zip等歸檔文件中加載.class文件
    • 從專有數據庫中提取.class文件
    • 將Java源代碼動態編譯為.class文件
  • 類的加載的最終產品是位於內存中的Class對象
  • Calss對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的接口
  • 有兩種類型的類加載器
    • Java虛擬機自帶的類加載器
      • 根類加載器(Bootstrap):該加載器沒有父加載器。他負責加載虛擬機的核心類庫,如java.lang.*等。根類加載器從系統屬性sun.boot.class.path所指定的目錄中加載類庫。根類加載器的實現依賴於底層操作系統,呀沒有繼承java.lang.CalssLoader類
      • 擴展類加載器(Extension):父加載器為根加載器。從java.ext.dirs系統屬性所指定的目錄中加載類庫,或者從JDK的安裝目錄的jre\lib\ext子目錄(擴展目錄)下加載類庫,如果用戶創建的JAR文件放在這個目錄下,也會自動由擴展類加載器加載。擴展類加載器是純Java類,是java.lang.ClassLoader類的子類
      • 系統(應用)類加載器(System):父加載器為擴展加載器。從環境變量classpath或者系統屬性java.class.path所指定的目錄中加載類,是用戶自定義類加載器的默認父加載器。系統類加載器是純Java類,是java.lang.ClassLoader類的子類
    • 用戶自定義的類加載器
      • java.lang.ClassLoader的子類
      • 用戶可以定製類的加載方式
  • 類加載器並不需要等到某個類被“首次使用”時再加載他
  • JVM規範允許類加載器在預料某個類將要被使用時就預先加載他,如果在預先加載的過程中遇到了.class文件缺失或存在錯誤,類加載器必須在程序首次主動使用時才報告錯誤(LinkageError錯誤)。如果這個類一直沒有被程序主動使用,那麼類加載器就不會報告錯誤

類的連接

類被加載后,就進入連接階段。連接就是將已經讀入到內存中的類的二進制數據合併到虛擬機的運行時環境中去

類的驗證

類的驗證的內容

  • 類文件的結構檢查
  • 語義檢查
  • 字節碼驗證
  • 二進制兼容性驗證

類的準備

在準備階段,Java虛擬機為類的靜態變量分配內存,並設置默認的初始值。例如對於下面的Sample類,在準備階段,將為int類型的靜態變量i分配4個字節的內存空間,並且賦默認值0;為long類型的靜態變量j分配8個字節的內存空間,並賦予默認值0

public class Sample {
    private static int i = 8;
    private static long j = 8L;
    ......
}

類的初始化

在初始化階段,Java虛擬機執行類的初始化語句,為類的靜態變量賦予初始值。在程序中,靜態變量的初始化有兩種途徑:

  • 在靜態變量的聲明處初始化
  • 在靜態代碼塊中初始化

靜態變量的聲明語句,預計靜態代碼塊都被看作類的初始化語句,Java虛擬機會按照初始化語句在類文件中的先後順序來依次執行他們

類的初始化步驟

  • 假如這個類還沒有被加載和連接誒,需要先進行加載和連接
  • 假如類存在直接父類,並且這個父類還沒有被初始化,需要先初始化直接父類
  • 假如類中存在初始化語句,需要依次執行這些初始化語句

類的初始化時機

  • 當Java虛擬機初始化一個類時,要求他的所有父類都已經被初始化,但是這條規則並不適用於接口

    • 在初始化一個類時,並不會先初始化他所實現的接口
    • 在初始化一個接口時,並不會先初始化他的父接口

    因此,一個父接口並不會因為他的子接口或實現類的初始化而初始化,只有當程序首次使用特定接口的靜態變量時,才會導致該接口的初始化。代碼參照代碼理解-接口的初始化

  • 只有當程序訪問的靜態變量或者靜態方法確實在當前類或者當前接口中定義時,才認為是對類或接口的主動使用

  • 調用ClassLoader類的loadClass方法加載一個類,並不是對類的主動使用,不會導致類的初始化

拓展部分

類實例化

類的生命周期除了前文提到的加載、連接、初始化之外,還有類示例化,垃圾回收和對象終結

  • 為新的對象分配內存
  • 為實例變量賦予默認值
  • 為實例變量賦予正確的初始值
  • Java編譯器為它編譯的每一個類都至少生成一個實例初始化方法,在Java的class文件中,這個實例初始化方法被稱為<init>。針對源代碼中每一個類的構造方法,Java編譯器都產生一個<init>方法

類的卸載

  • 當一個類被加載、連接和初始化后,它的生命周期就開始了。當代表該類的Class對象不再被引用,即不可觸及時,Class對象就會結束生命周期,這個類在方法區內的數據也會被卸載,從而結束自己的生命周期
  • 一個類何時結束生命周期,取決於代表它的Class對象何時結束生命周期
  • 由Java虛擬機自帶的類加載器所加載的類,在虛擬機的生命周期中,始終不會被卸載。Java虛擬機本身會始終引用這些類加載器,而這類加載器則會始終引用它們所加載的類的Class對象,因此這些Class對象始終是可觸及的;由用戶自定義的類加載器所加載的類是可以被卸載的

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

【其他文章推薦】

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

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

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

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

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

前蘋果資深副總 傳接手電動車計畫

日前國外媒體《The Information》才報導,蘋果的電動車計畫可能順延至 2021 年;而《華爾街日報》引述知情人士的說法,曾任蘋果資深副總裁的Bob Mansfield 將接掌電動車計畫。

熟知蘋果電動車計畫Project Titan 的內部人士向《華爾街日報》透露,曾任技術部門資深副總裁的Bob Mansfield 將接手這項計畫。不過,目前蘋果官方與Bob Mansfield 本人都不願對於報導內容發表任何評論。

Bob Mansfield 於1999 年加入蘋果,在已故執行長Steve Jobs 底下出任管理階層;過去他曾主導硬體開發工程,產品包括MacBook Air、iMac、iPad 等。蘋果曾在2012 年宣布Bob Mansfield 將要退休,但後來又被執行長Tim Cook 說服、高薪留任公司;2013 年開始他從經營團隊名單隱身,官方僅表示他負責特別專案項目,並直接向Tim Cook 彙報。

Bob Mansfield 與像是設計長Jonathan Ive 等高層一向較少在公開場合露面,而在產品發表會或精心製作的產品影片當中可見他的身影。不過本月份開始,蘋果員工發現負責電動車計畫的資深經理轉而向Bob Mansfield 彙報。

當重點產品iPhone 銷售成長放緩、影響營收與獲利後,新的發展計畫成了蘋果迫切需要的項目。該公司雖未公開承認正在開發一款電動車,不過國外媒體陸續報導,已有數百名員工加入專案,並且聘請來自汽車產業的電池技術與自動駕駛專家,這項計畫可望成為未來推動蘋果成長的發展項目之一。

(本文授權自《》──〈〉)

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

【其他文章推薦】

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

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

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

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

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

眾泰汽車被舉報騙補 借殼金馬股份或生變

昨日一則關於眾泰汽車涉嫌騙取國家補貼的舉報,在網路上被迅速傳播:江蘇宿遷眾泰經銷商舉報眾泰汽車為了拿到新能源補貼,在國家大力查處騙補之時,大量生產眾泰新能源雲100早產車。由於生產日期與全身玻璃相差3-5個月,車管所拒絕過戶導致大量車主無法上牌,經銷商無法幫車主解決此問題於是舉報廠家。  
 
專項嚴打   恰恰是面臨著2016年新能源補貼將降低的時間節點,也激發了新能源汽車銷量出現井噴。據報導,2015年11月我國的新能源商用車單月產量超過全球其他國家總和。新能源汽車產銷超常增速背後的“虛火”,也引起了管理部門的關注。   2016年1月初,國家資訊中心資源開發部主任徐長明公開表達了對新能源汽車的質疑, 正是在這樣的質疑聲中,2016年1月21日,四部委聯合發佈《關於開展新能源汽車推廣應用核查工作的通知》,隨後這一“騙補核查行動”更是上升為由國務院牽頭。5月28日,財政部官網消息稱,關於新能源汽車推廣騙補的現場核查已經完成,目前處於會審階段,但並未透露任何核查細節。  
眾泰之危   值得關注的是,上市公司金馬股份已經於今年3月28日發佈公告,計畫以116億元的估值收購眾泰汽車全部股權。然而金馬股份卻在7月6日撤回了收購方案申報,眾泰汽車的借殼上市計畫也戛然而止。恰在這樣一個敏感的時點,關於眾泰汽車騙取新能源汽車補貼的舉報現於網路,並被快速傳播。   也正是由於眾泰汽車的盈利對於新能源汽車補貼的高度依賴,也使得針對該公司騙取新能源補貼的舉報備受關注,相關人士表示,如果這個舉報最終被證實,那麼對於眾泰汽車的借殼上市而言,就是絕殺,不僅是經營層面違法違規、可能面臨高額處罰,而且從最終的財務影響來看也會涉及到財務造假。   文章來源:環球網

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

【其他文章推薦】

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

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

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

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

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