Java基礎系列5:Java代碼的執行順序

該系列博文會告訴你如何從入門到進階,一步步地學習Java基礎知識,並上手進行實戰,接着了解每個Java知識點背後的實現原理,更完整地了解整個Java技術體系,形成自己的知識框架。

 

一、構造方法

構造方法(或構造函數)是類的一種特殊方法,用來初始化類的一個新的對象。Java 中的每個類都有一個默認的構造方法,它必須具有和類名相同的名稱,而且沒有返回類型。構造方法的默認返回類型就是對象類型本身,並且構造方法不能被 static、final、synchronized、abstract 和 native 修飾。

提示:構造方法用於初始化一個新對象,所以用 static 修飾沒有意義;構造方法不能被子類繼承,所以用 final 和 abstract 修飾沒有意義;多個線程不會同時創建內存地址相同的同一個對象,所以用 synchronized 修飾沒有必要。

構造方法的語法格式如下:

public class Person {
	
	/**
	 * 1.構造方法沒有返回值 默認返回類型就是對象類型本身
	 * 2.構造方法的方法名和類名相同
	 */
	
	//無參構造方法
	public Person() {
		System.out.println("我是無參構造方法");
	}
	
	//有參構造方法
	public Person(String username,Integer age) {
		System.out.println("我是有參構造"+"姓名:"+username+"  密碼:"+age);
	}
	
	public static void main(String[] args) {
		Person p1=new Person();//調用無參構造
		
		Person p2=new Person("小王",12);//調用有參構造
	}

}

  

關於構造方法,需要注意:

  • 如何調用:
    • 構造方法在實例化的時候調用,如上述代碼中的Person p1=new Person(),這裏便調用了Person類的無參構造,構造方法由系統自動調用
  • 構造函數重載
    • 我們知道方法可以重載(方法名相同,參數列表不同),那麼構造方法也是方法的一種,當然也可以繼承,如上述代碼中的兩個構造方法,一個無參構造方法,一個帶兩個參數的構造方法。
    • 當有多個構造方法時,程序會在你創建類時根據你傳入的參數決定調用哪個構造方法
  • 默認構造方法
    • 細心的讀者可能會有疑問,之前創建類的時候我並沒有聲明構造函數,但是也可以創建類,是不是可以說類不需要構造函數也可以創建。不是滴,當你沒有显示聲明構造函數時,程序會自動生成一個默認的無參構造函數
    • 並且該構造函數的權限是隨着類的改變而改變的(類為public,構造函數也為public;類改為private,構造函數也改為private);而當該類一旦聲明了構造函數以後,java 是不會再給該類分配默認的構造函數。就是說,一旦你聲明了構造函數,並且該構造函數有形參,那麼你就不能pen ipen=new pen();像這樣聲明一個對象了。
  • 構造方法作用:
    • 構造函數是用於對象初始化
    • 一個對象建立,構造函數只運行一次,而一般方法可以被該對象調用多次。

 

二、代碼塊

1、普通代碼塊:

普通代碼塊是我們用得最多的也是最普遍的,它就是在方法名後面用{}括起來的代碼段。普通代碼塊是不能夠單獨存在的,它必須要緊跟在方法名後面。同時也必須要使用方法名調用它。

public class Test {
    public void test(){
        System.out.println("普通代碼塊");
    }
}

  

2、構造代碼塊:

在類中直接定義沒有任何修飾符、前綴、後綴的代碼塊即為構造代碼塊。我們明白一個類必須至少有一個構造函數,構造函數在生成對象時被調用。構造代碼塊和構造函數一樣同樣是在生成一個對象時被調用

public class Test{
  {
      System.out.println("我是構造代碼塊");
  }
}    

 

注意:

  • 構造代碼塊的作用是給對象初始化。
  • 對象一建立就調用構造代碼塊了,而且優於構造函數執行。這裏強調一下,有對象創建,才會執行構造代碼塊,類不能調用構造代碼塊的,而且構造代碼塊與構造函數的執行順序是前者先於後者執行。
  • 構造代碼塊與構造函數的區別是:構造代碼塊是給所有對象進行統一初始化,而構造函數是給對應的對象初始化,因為構造函數是可以多個的,運行哪個構造函數就會建立什麼樣的對象,但無論建立哪個對象,都會先執行相同的構造代碼塊。也就是說,構造代碼塊中定義的是不同對象共性的初始化內容。

  

 

3、靜態代碼塊:

想到靜態我們就會想到static,靜態代碼塊就是用static修飾的用{}括起來的代碼段,它的主要目的就是對靜態屬性進行初始化。

public class Test {
    static{
        System.out.println("靜態代碼塊");
    }
}

  

注意:

  • 靜態代碼塊隨着類的加載而執行,而且只會執行一次,並優於主函數。具體說靜態代碼塊由類調用,類調用時先執行靜態代碼塊,然後才執行主函數。
  • 靜態代碼塊是給類初始化的,而構造代碼塊是給對象初始化的。
  • 靜態代碼塊中的變量是局部變量,和普通方法中的局部變量沒有區別。
  • 一個類中可以有多個靜態代碼塊。

 

三、Java類的初始化順序

1、一個類的情況:

A:

public class Test {
	
	public Test(){
		System.out.println("Test構造函數");
	}
	
	{
		System.out.println("Test構造代碼塊");
	}
	
	static {
		System.out.println("靜態代碼塊");
	}
	
	
	public static void main(String[] args) {
		
	}

}

  

結果:

靜態代碼塊

  

B:

public class Test {
	
	public Test(){
		System.out.println("Test構造函數");
	}
	
	{
		System.out.println("Test構造代碼塊");
	}
	
	static {
		System.out.println("靜態代碼塊");
	}
	
	
	public static void main(String[] args) {
		Test t=new Test();//創建了一個對象
		
	}

}

  

這段代碼相比於上述代碼多了一個創建對象的代碼

結果:

靜態代碼塊
Test構造代碼塊
Test構造函數

  

C:

public class Test {
	
	public Test(){
		System.out.println("Test構造函數");
	}
	
	{
		System.out.println("Test構造代碼塊");
	}
	
	static {
		System.out.println("靜態代碼塊");
	}
	
	
	public static void main(String[] args) {
		Test t1=new Test();//創建了一個對象
		
		Test t2=new Test();
		
	}

}

  

結果:

靜態代碼塊
Test構造代碼塊
Test構造函數
Test構造代碼塊
Test構造函數

  

由此結果可以看出:靜態代碼塊只會在類加載的時候執行一次,而構造函數和構造代碼塊則會在每次創建對象的都會執行一次

 

對於一個類而言,按照如下順序執行:

  1. 執行靜態代碼塊
  2. 執行構造代碼塊
  3. 執行構造函數

對於靜態變量、靜態初始化塊、變量、初始化塊、構造器,它們的初始化順序依次是(靜態變量、靜態初始化塊)>(變量、初始化塊)>構造器。

 

D:

public class Test {
	
	//靜態變量
	public static String staticField="靜態變量";
	
	//變量
	public String field="變量";
	
	//靜態初始化塊
	static {
		System.out.println(staticField);
		System.out.println("靜態初始化塊");
	}
	
	{
		System.out.println(field);
		System.out.println("初始化塊");
	}
	
	//構造函數
	public Test() {
		System.out.println("構造函數");
	}
	
	public static void main(String[] args) {
		Test t=new Test();
	}

}

  

結果:

靜態變量
靜態初始化塊
變量
初始化塊
構造函數

  

2、繼承情況下的代碼執行順序:

class TestA{
	public TestA() {
		System.out.println("A的構造函數");
	}
	
	{
		System.out.println("A的構造代碼塊");
	}
	
	static {
		System.out.println("A的靜態代碼塊");
	}
}

public class TestB extends TestA {
	
	public TestB() {
		System.out.println("B的構造函數");
	}
	
	{
		System.out.println("B的構造代碼塊");
	}
	
	static {
		System.out.println("B的靜態代碼塊");
	}

	public static void main(String[] args) {
		TestB t=new TestB();
	}
	
}

  

這裡有兩個類,屬於繼承的關係,讀者先不要看答案,自己思考一下結果是啥?

1 A的靜態代碼塊
2 B的靜態代碼塊
3 A的構造代碼塊
4 A的構造函數
5 B的構造代碼塊
6 B的構造函數

結果

 

 

當設計到繼承時,代碼的執行順序如下:

1、執行父類的靜態代碼塊,並初始化父類的靜態成員

2、執行子類的靜態代碼塊,並初始化子類的靜態成員

3、執行父類的構造代碼塊,執行父類的構造函數,並初始化父類的普通成員變量

4、執行子類的構造代碼塊,執行子類的構造函數,並初始化子類的普通成員變量

 

Java初始化流程圖:

 

 

 

class Parent {
	/* 靜態變量 */
	public static String p_StaticField = "父類--靜態變量";
	/* 變量 */
	public String p_Field = "父類--變量";
	protected int i = 9;
	protected int j = 0;
	/* 靜態初始化塊 */
	static {
		System.out.println(p_StaticField);
		System.out.println("父類--靜態初始化塊");
	}
	/* 初始化塊 */
	{
		System.out.println(p_Field);
		System.out.println("父類--初始化塊");
	}

	/* 構造器 */
	public Parent() {
		System.out.println("父類--構造器");
		System.out.println("i=" + i + ", j=" + j);
		j = 20;
	}
}

public class SubClass extends Parent {
	/* 靜態變量 */
	public static String s_StaticField = "子類--靜態變量";
	/* 變量 */
	public String s_Field = "子類--變量";
	/* 靜態初始化塊 */
	static {
		System.out.println(s_StaticField);
		System.out.println("子類--靜態初始化塊");
	}
	/* 初始化塊 */
	{
		System.out.println(s_Field);
		System.out.println("子類--初始化塊");
	}

	/* 構造器 */
	public SubClass() {
		System.out.println("子類--構造器");
		System.out.println("i=" + i + ",j=" + j);
	}

	/* 程序入口 */
	public static void main(String[] args) {
		System.out.println("子類main方法");
		new SubClass();
	}
}

  

結果:

父類--靜態變量
父類--靜態初始化塊
子類--靜態變量
子類--靜態初始化塊
子類main方法
父類--變量
父類--初始化塊
父類--構造器
i=9, j=0
子類--變量
子類--初始化塊
子類--構造器
i=9,j=20

  

(1)訪問SubClass.main(),(這是一個static方法),於是裝載器就會為你尋找已經編譯的SubClass類的代碼(也就是SubClass.class文件)。在裝載的過程中,裝載器注意到它有一個基類(也就是extends所要表示的意思),於是它再裝載基類。不管你創不創建基類對象,這個過程總會發生。如果基類還有基類,那麼第二個基類也會被裝載,依此類推。

(2)執行根基類的static初始化,然後是下一個派生類的static初始化,依此類推。這個順序非常重要,因為派生類的“static初始化”有可能要依賴基類成員的正確初始化。

(3)當所有必要的類都已經裝載結束,開始執行main()方法體,並用new SubClass()創建對象。

(4)類SubClass存在父類,則調用父類的構造函數,你可以使用super來指定調用哪個構造函數。基類的構造過程以及構造順序,同派生類的相同。首先基類中各個變量按照字面順序進行初始化,然後執行基類的構造函數的其餘部分。

(5)對子類成員數據按照它們聲明的順序初始化,執行子類構造函數的其餘部分。 

 

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

【其他文章推薦】

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

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

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

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

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

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

01-MyBatis啟動流程分析

目錄

MyBatis簡單介紹

MyBatis是一個持久層框架,使用簡單,學習成本較低。可以執行自己手寫的SQL語句,比較靈活。但是MyBatis的自動化程度不高,移植性也不高,有時從一個數據庫遷移到另外一個數據庫的時候需要自己修改配置。

一個Mybatis最簡單的使用列子如下:

public class UserDaoTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws Exception{
        ClassPathResource resource = new ClassPathResource("mybatis-config.xml");
        InputStream inputStream = resource.getInputStream();
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void selectUserTest(){
        String id = "{0003CCCA-AEA9-4A1E-A3CC-06D884BA3906}";
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CbondissuerMapper cbondissuerMapper = sqlSession.getMapper(CbondissuerMapper.class);
        Cbondissuer cbondissuer = cbondissuerMapper.selectByPrimaryKey(id);
        System.out.println(cbondissuer);
        sqlSession.close();
    }

}
  • 從配置文件(通常是XML文件)得到SessionFactory;
  • 從SessionFactory得到SQLSession;
  • 通過SqlSession進行CRUD和事務的操作;
  • 執行完相關操作之後關閉Session。

啟動流程分析

本博客只涉及創建SessionFactory,以及從SessionFactory獲取SqlSession的流程。具體執行Sql的流程會在其他博客中分析。

ClassPathResource resource = new ClassPathResource("mybatis-config.xml");
InputStream inputStream = resource.getInputStream();
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

通過上面代碼發現,創建SqlSessionFactory的代碼在SqlSessionFactoryBuilder中,進去一探究竟:

//整個過程就是將配置文件解析成Configration對象,然後創建SqlSessionFactory的過程
//Configuration是SqlSessionFactory的一個內部屬性
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

下面我們看下解析配置文件過程中的一些細節。

先給出一個配置文件的列子:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--SqlSessionFactoryBuilder中配置的配置文件的優先級最高;config.properties配置文件的優先級次之;properties標籤中的配置優先級最低 -->
    <properties resource="org/mybatis/example/config.properties">
      <property name="username" value="dev_user"/>
      <property name="password" value="F2Fa3!33TYyg"/>
    </properties>

    <!--一些重要的全局配置-->
    <settings>
    <setting name="cacheEnabled" value="true"/>
    <!--<setting name="lazyLoadingEnabled" value="true"/>-->
    <!--<setting name="multipleResultSetsEnabled" value="true"/>-->
    <!--<setting name="useColumnLabel" value="true"/>-->
    <!--<setting name="useGeneratedKeys" value="false"/>-->
    <!--<setting name="autoMappingBehavior" value="PARTIAL"/>-->
    <!--<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>-->
    <!--<setting name="defaultExecutorType" value="SIMPLE"/>-->
    <!--<setting name="defaultStatementTimeout" value="25"/>-->
    <!--<setting name="defaultFetchSize" value="100"/>-->
    <!--<setting name="safeRowBoundsEnabled" value="false"/>-->
    <!--<setting name="mapUnderscoreToCamelCase" value="false"/>-->
    <!--<setting name="localCacheScope" value="STATEMENT"/>-->
    <!--<setting name="jdbcTypeForNull" value="OTHER"/>-->
    <!--<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>-->
    <!--<setting name="logImpl" value="STDOUT_LOGGING" />-->
    </settings>

    <typeAliases>

    </typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--默認值為 false,當該參數設置為 true 時,如果 pageSize=0 或者 RowBounds.limit = 0 就會查詢出全部的結果-->
            <!--如果某些查詢數據量非常大,不應該允許查出所有數據-->
            <property name="pageSizeZero" value="true"/>
        </plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://10.59.97.10:3308/windty"/>
                <property name="username" value="windty_opr"/>
                <property name="password" value="windty!234"/>
            </dataSource>
        </environment>
    </environments>

    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql" />
        <property name="Oracle" value="oracle" />
    </databaseIdProvider>

    <mappers>
        <!--這邊可以使用package和resource兩種方式加載mapper-->
        <!--<package name="包名"/>-->
        <!--<mapper resource="./mappers/SysUserMapper.xml"/>-->
        <mapper resource="./mappers/CbondissuerMapper.xml"/>
    </mappers>

</configuration>

下面是解析配置文件的核心方法:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      //解析properties標籤,並set到Configration對象中
      //在properties配置屬性后,在Mybatis的配置文件中就可以使用${key}的形式使用了。
      propertiesElement(root.evalNode("properties"));
      
      //解析setting標籤的配置
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      //添加vfs的自定義實現,這個功能不怎麼用
      loadCustomVfs(settings);
        
      //配置類的別名,配置后就可以用別名來替代全限定名
      //mybatis默認設置了很多別名,參考附錄部分
      typeAliasesElement(root.evalNode("typeAliases"));
        
      //解析攔截器和攔截器的屬性,set到Configration的interceptorChain中
      //MyBatis 允許你在已映射語句執行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:
      //Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
        //ParameterHandler (getParameterObject, setParameters)
        //ResultSetHandler (handleResultSets, handleOutputParameters)
        //StatementHandler (prepare, parameterize, batch, update, query)
      pluginElement(root.evalNode("plugins"));
      
      //Mybatis創建對象是會使用objectFactory來創建對象,一般情況下不會自己配置這個objectFactory,使用系統默認的objectFactory就好了
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
       
      //設置在setting標籤中配置的配置
      settingsElement(settings);
   
      //解析環境信息,包括事物管理器和數據源,SqlSessionFactoryBuilder在解析時需要指定環境id,如果不指定的話,會選擇默認的環境;
      //最後將這些信息set到Configration的Environment屬性裏面
      environmentsElement(root.evalNode("environments"));
        
      //
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        
      //無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。解析typeHandler。
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析Mapper
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

上面解析流程結束後會生成一個Configration對象,包含所有配置信息,然後會創建一個SqlSessionFactory對象,這個對象包含了Configration對象。

下面是openSession的過程:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //獲取執行器,這邊獲得的執行器已經代理攔截器的功能(見下面代碼)
      final Executor executor = configuration.newExecutor(tx, execType);
      //根據獲取的執行器創建SqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
//interceptorChain生成代理類,具體參見Plugin這個類的方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

到此為止,我們已經獲得了SqlSession,拿到SqlSession就可以執行各種CRUD方法了。

簡單總結

對於MyBatis啟動的流程(獲取SqlSession的過程)這邊簡單總結下:

  • SqlSessionFactoryBuilder解析配置文件,包括屬性配置、別名配置、攔截器配置、環境(數據源和事務管理器)、Mapper配置等;解析完這些配置後會生成一個Configration對象,這個對象中包含了MyBatis需要的所有配置,然後會用這個Configration對象創建一個SqlSessionFactory對象,這個對象中包含了Configration對象;
  • 拿到SqlSessionFactory對象后,會調用SqlSessionFactory的openSesison方法,這個方法會創建一個Sql執行器(Executor),這個Sql執行器會代理你配置的攔截器方法
  • 獲得上面的Sql執行器后,會創建一個SqlSession(默認使用DefaultSqlSession),這個SqlSession中也包含了Configration對象,所以通過SqlSession也能拿到全局配置;
  • 獲得SqlSession對象后就能執行各種CRUD方法了。

SQL的具體執行流程見後續博客。

一些重要類總結:

  • SqlSessionFactory
  • SqlSessionFactoryBuilder
  • SqlSession(默認使用DefaultSqlSession)
  • Plugin、InterceptorChain的pluginAll方法

附錄

MyBatis內置別名轉換

//TypeAliasRegistry
registerAlias("string", String.class);

registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);

registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);

registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);

registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);

registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);

registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);

registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);

registerAlias("ResultSet", ResultSet.class);

參考

https://blog.csdn.net/luanlouis/article/details/40422941

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

減量力道不足 國際智庫提長期氣候策略

文:楊竣文(台灣大學政治學研究所碩士生)

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

【其他文章推薦】

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

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

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

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

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

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

馬拉威保護區采采蠅暴增 民憂非洲昏睡病再起

摘錄自2019年12月7日公共電視報導

馬拉威國家公園520隻大象,最近剛遷到新的野生動物保護區,希望能促進繁衍,但沒想到經常與大象共生的采采蠅,數量也大為增加,由於采采蠅會傳染寄生蟲,釀成致命的非洲昏睡病,附近民眾非常擔憂。

采采蠅不論公母都會吸血,被牠叮咬的話,就可能感染非洲錐蟲症,症狀跟瘧疾非常類似,很容易被誤診,釀成致命危險。「非洲錐蟲症」又稱為非洲昏睡病,主要出現在非洲撒哈拉以南的36個國家,初期症狀是發燒、頭痛,如果侵入腦部引起腦膜炎,可能導致神智不清,癲癇、昏睡不醒而死。非洲昏睡病在1890年代曾經造成數十萬人死亡,重創區域畜牧業跟農業,世界衛生組織直到2008年才控制住這種疾病。

動保NGO團體African Parks經營經理羅伯特說,「這有點諷刺,因為這是成功(大象遷移)的負面效應,動物數量增加所造成的後果之一,就是采采蠅的數量也增加了。」

為了防止非洲昏睡病擴散,動保團體跟馬拉威政府合作,在大象保護區內設置了600個陷阱與標靶,用采采蠅喜歡的藍色布料誘捕消滅牠們。此外也將增加醫療專業人手,並加強訓練,提高早期確診率,減少死亡病例。

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

日新潟診所倉庫 赫見3頭熊準備冬眠

摘錄自2019年12月8日中央社、9日公共電視報導

氣候暖化讓各地生態都在改變,日本新潟有診所發現三頭熊疑似找不到適合地方冬眠,居然把診所倉庫,當成冬眠的場所。

日本放送協會(NHK)報導,8日上午8時45分(台灣時間7時45分)左右,南魚沼市二日町一家診所業者進入診所時發現有熊,立即打電話報警說:「診所內有一頭熊。」NHK記者現場報導,「現在可能是要將熊送上車運走,好像是小熊的樣子,感覺掙扎得相當厲害。」 當地政府表示,預計將把3頭熊帶到野外放生

警察在發現熊之後,在診所倉庫周邊架設障礙物,下午3時30左右對熊發射麻醉槍。熟知熊生態的新潟大學農學部(農學系)教授箕口秀夫表示,目前正是熊的冬眠期,這兩頭熊可能無法找到岩洞或木洞等適當的地方冬眠,所以選這家診所當冬眠地。今年熊吃的食物不足,很多熊來到山下有住家的地方覓食,或許這兩頭熊是冬眠前夕在市區附近覓食。對熊而言,這是緊急措施狀況。

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

【其他文章推薦】

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

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

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

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

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

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

非洲南部嚴重旱災 世界最大瀑布幾乎消失

摘錄自2019年12月7日中央社報導

位於非洲南部尚比西河(Zambezi River)中游, 坐落於尚比亞與辛巴威的交界處,高108公尺、寬1708公尺,被認為是世界上最大的瀑布,是該區域最大旅遊景點,數十年來吸引了數百萬旅客造訪辛巴威及尚比亞一睹奇景。

然而,路透社與英國「每日郵報」報導,維多利亞瀑布(Victoria Falls),非洲南部在嚴重旱災衝擊下,水位降至25年來最低,這場世紀最嚴重旱災,造成維多利亞瀑布減緩為細流,加劇氣候變遷可能破壞瀑布的憂慮。通常於乾季瀑布水流會減少,但官員表示,今年水位下降程度前所未見。

Shocking before and after photos show Victoria Falls almost completely dried up

— Daily Mail Online (@MailOnline)

The Victoria Falls, which draws millions of holidaymakers to Zimbabwe and Zambia, has shrunk to a trickle, fuelling fears that climate change could kill one of the region’s biggest tourist attractions

— Reuters (@Reuters)

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

2020氣候變遷績效報告:31國碳排下降 台灣退步居倒數第三

環境資訊中心綜合外電;鄒敏惠編譯、陳文姿報導

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

【其他文章推薦】

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

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

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

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

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

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

烏干達暴雨不斷災情嚴重 已300死、數百萬人流離失所

摘錄自2019年12月9日自由時報烏干達報導

烏干達數周的降雨造成嚴重的水災,根據紅十字會8日表示,已發現17名屍體,死亡人口持續增加,目前仍有許多人失蹤。這也是上周暴雨,烏干達地區最新公告的死者數據。

綜合外媒報導,自10月起,東非各國遭到暴雨的侵襲,包括烏干達、肯亞等國。根據聯合國資料,過去兩個月中,洪水和山區滑坡摧毀了東非大部分地區,造成近300人死亡,數百萬人流離失所。

東非國家正在經歷第二個雨季,該雨季已在大部分地區達到頂峰。烏干達國家氣象局預測,整個12月將繼續出現強降雨。暴雨在烏干達低窪地區造成了破壞性的洪災,並在山區造成了滑坡。破壞性的災害襲擊了烏干達各地的種植園和農作物。

根據飢荒預警系統網絡(Famine Early Warning Systems Network)的數據,在過去的兩個月中,大雨使東非部分地區遭受嚴重破壞,非洲之角的降雨量比平均水平高出300%(10月至11月中旬)。

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

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

減少汽車碳排雙管齊下,南韓要衝氫動力汽車

全球各國很少在什麼事情上取得共識,對抗氣候變遷倒是頭一遭,讓各懷鬼胎的人類能夠一致以減少排放溫室氣體為目標。在這個願景下,各國想盡辦法減少碳排放,如台灣廠商將電動機車變成一種時尚,南韓則是立志要大力推廣氫動力汽車。

目前汽車製造商包括現代、豐田都有生產氫動力車,現代在 2013 年開始大量生產氫動力車,主要是在歐洲與加州銷售,豐田是在去年開始販售第一款消費性燃料電池汽車,但因全球氫動力車因為價格太高與缺少加氣站,銷售仍不見起色。   《華爾街日報》報導,巴黎氣候變遷會議之後,南韓宣誓未來五年要增加氫動力車銷售數量從現在的 50 輛到 9,000 輛,2030 年要到 63 萬輛,等於每賣出十輛新車,就有一輛是氫動力汽車。氫動力車結合氫與氧來產生電力,副產品就是從排氣管排放的水蒸氣。   南韓政府將補貼每輛氫動力車 275 萬韓圜,約當 23,250 美元,氫動力車售價大約 8,500 萬韓圜,接近 240 萬台幣,補貼約 3%。   除了補貼,南韓還要增加加氣站從目前的 10 座,到 2030 年的 520 座。南韓宣誓未來五年,減少運輸工具碳排放 11%,約 380 萬噸。低碳排放汽車包括混合動力車與電動車將在 2020 年占南韓總汽車銷售量的 20%,現在約 2%。

(首圖來源:)

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

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

【其他文章推薦】

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

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

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

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

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

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

豐田概念電動汽車uBox:想要什麼可以自己定制

近日,豐田和克萊門森大學國際汽車研究中心合作,為下一代的司機創造出了一個全新的概念電動汽車——uBox。

豐田曾經發起了一個名為“Deep Orange”的合作專案,uBox正是項目的結晶。

據瞭解,豐田和克萊門森大學在過去的兩年裡一直致力於這款概念車的開發工作。uBox概念車使用了方形的設計、自動式車門,並用複合碳纖維和鋁合金支撐著一塊弧形玻璃。其全新設計的套件裝備均極大程度提升了整車的舒適性與功能性。

豐田表示汽車的內部配置可以根據司機的品味進行配置。座位安裝在導軌上,並且通風口、內飾、車內顏色方案都可以定制,可以下載新設計然後用3D印表機重新構建。它還擁有一個110伏的插座,可以為筆記型電腦等眾多設備充電。

至於動力系統方面,除了豐田將在uBox上搭載一台電動機引擎之外,目前並沒有獲得更多這方面的消息。

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

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