整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          初識HTML,什么是HTML?

          eb標準:

          由于不同瀏覽器解析出來的網頁效果可能不同,所以需要通過web標準對其進行約束使其一致,主要包括三個方面:

          結構標準:

          結構用于對網頁元素進行整理和分類,主要指的是HTML。

          表現標準

          表現用于設置網頁元素的版式、顏色、大小等外觀樣式,主要指的是CSS。

          行為標準:

          行為是指網頁模型的定義及交互的編寫,主要指的是 JavaScript。

          初識HTML:

          html 全稱 Hyper Text Markup Language ,中文譯為:“超文本標記語言” ,描述網頁的一種語言。

          HTML發展:

          XHTML 是一個 W3C 標準,可擴展超文本標簽語言(EXtensible HyperText Markup Language),更嚴格更純凈的 HTML 版本,作為一種 XML 應用被重新定義的 HTML。



          HTML中的注釋

           <!-- 注釋標簽:注釋的內容 -->

          條件注釋:

          條件注釋的作用是:定義只有Internet Explorer才執行條件注釋中的html標簽。

          
              <!--[if IE 8]>
                  .... some HTML here ....
              <![endif]-->

          HTML骨架:

          <!DOCTYPE html> <!-- 聲明文檔類型版本為html5 -->
          <html lang="en"> <!-- 網頁的跟標簽,lang=""用來設置網頁語言,其值還有zh-CN中文簡體、fr法語等,設置后當系統設置語言和網頁語言發生沖突時會提示是否翻譯網頁 -->
              <head> <!-- 網頁的頭部 -->
                  <meta charset='UTF-8'> <!-- 聲明字符編碼,其值還有gbk和gb2312 -->
                  <meta name="viewport" content="width=device-width,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0,initial-scale=1.0"> <!-- 開啟移動端視口 -->
                  <meta name="apple-mobile-web-app-capable" content="yes"> <!-- 開啟ios快捷啟動方式 -->
                  <meta name="apple-mobile-web-app-status-bar-style" content="black"> <!-- 設置iOS頂部通欄樣式 -->
                  <meta name="format-detection" content="telephone=no"> <!-- 遇到數字不轉成電話號碼 -->
                  <meta http-equiv="X-UA-Compatible" content="ie=edge"> <!-- X-UA-Compatible是針對IE瀏覽器做兼容的,ie=edge表示兼容edge,若后面ie=7,則表示兼容IE7 -->
                  <meta name='keywords' content='This is a key words'> <!-- 網站搜索關鍵字 -->
                  <meta name='description' content='this is description'> <!-- 描述網站的信息 -->
                  <link rel="shortcut icon" type="image/x-icon" href="圖片路徑 "/> <!--  網站的圖標,如果圖標是gif圖,則需要改:type="image/gif",引入網站圖標另一種方法:命名為favicon.ico文件放到網站根目錄下 -->
                  <link rel="stylesheet" type="text/css" href="css文件路徑"/> <!-- 引用css文件 -->
                  <base target="_blank"/> <!-- base標簽,定義這個網頁中a鏈接打開窗口的方式,其值還有_self -->
                  <title>標題</title> <!-- 網站的標題 -->
                  <style type="text/CSS">  /* 用來寫CSS代碼,type="text/CSS"可以省略 */
                      div{width:100px; height:100px; color:white;}
                  </style>
              </head>
              <body> <!-- 網頁的主體 -->
                  <h1>標題</h1> <!-- 標題標簽,共六個級,分別為:h1~h6,大小逐級遞減,h1在一個網頁中只允許出現一次。 -->
                  <p>段落</p> <!-- 段落標簽 -->
                  <hr/> <!-- 單線標簽,所有單標簽后面的關閉符均可以省略 -->
                  <br/> <!-- 換行標簽 -->
                  </div></div> <!-- 無語義化標簽布局用,上面的標簽是語義化標簽 -->
                  <span>span</span> <!-- 無語義化標簽分割用 -->                
                  <strong>加粗</strong> <!-- 加粗標簽 -->
                  <b>加粗</b> <!-- 加粗標簽 -->
                  <i>傾斜</i> <!-- 傾斜標簽 -->
                  <em>傾斜</em> <!-- 傾斜標簽 -->
                  <s>刪除線</s> <!-- 刪除標簽 -->
                  <del>刪除線</del> <!-- 刪除標簽 -->
                  <u>下劃線</u> <!-- 下劃線標簽 -->
                  <ins>下劃線</ins> <!-- 下劃線標簽 -->
                  <img src="圖片路徑" alt="圖片無法加載,提示文字" title="鼠標懸停,提示文體" border="2"/> <!-- 圖像標簽,border是邊框屬性,width和height屬性設置圖像的寬度和高度 -->
                  <a href="跳轉目標" target="_self">鏈接的命名</a> <!-- 鏈接標簽,target屬性為鏈接頁面打開的方式,默認值_self為自身打開;_blank為新窗口打開;_new為新窗口打開,相同頁面只會打開一個;_top跳出框架-->
                  <ul> <!-- 無序列表 -->
                      <li>列表項1</li>
                      <li>列表項2</li>
                      <li>列表項3</li>
                  </ul>
                  <ol type="A"> <!-- 有序列表,屬性type可以控制li序號的樣式,其屬性值有:1、A、a、I、i-->
                      <li>中國</li>
                      <li>美國</li>
                      <li>英國</li>
                  </ol>
                  <dl> <!-- 自定義列表 -->
                      <dt>分類1</dt> <!-- 分類名稱 -->
                      <dd>分類1第1項</dd> <!-- 類的項 -->
                      <dd>分類1第2項</dd>
                      <dt>分類2</dt>
                      <dd>分類2第1項</dd>
                      <dd>分類2第2項</dd>
                  </dl>
                  <table> <!-- 定義表格,table標簽實際就是一個四方塊框框,里面有單元格才會顯示出表格的樣子 -->
                  <caption>信息表</caption> <!-- 表格標題 -->
                  <tr> <!-- 定義行 -->
                      <th>姓名</th> <!-- 定義表頭,表頭文本有加粗居中效果 -->
                      <th>年齡</th>
                      <th>性別</th>
                  </tr>
                  <tr> <!-- 定義行 -->
                      <td>小明</td> <!-- 定義單元格,表格里面沒有列-->
                      <td>18</td>
                      <td>男</td>
                  </tr>
                  </table>
              </body>
          </html>

          提示:本文圖片等素材來源于網絡,若有侵權,請發郵件至郵箱:810665436@qq.com聯系筆者刪除。

          筆者:苦海123

          其它問題可通過以下方式聯系本人咨詢:

          QQ:810665436

          微信:ConstancyMan

          an 命令 是 Linux 下的幫助指令,通過 man 指令可以查看 Linux 中的指令幫助、配置文件幫助和編程幫助等信息。

          語法

          > man(選項)(參數)
          

          選項

          -a:在所有的man幫助手冊中搜索;
          -f:等價于whatis指令,顯示給定關鍵字的簡短描述信息;
          -P:指定內容時使用分頁程序;
          -M:指定man手冊搜索的路徑。
          

          參數

          • 數字:指定從哪本 man 手冊中搜索幫助;
          • 關鍵字:指定要搜索幫助的關鍵字。

          數字代表內容

          1:用戶在shell環境可操作的命令或執行文件;
          2:系統內核可調用的函數與工具等
          3:一些常用的函數(function)與函數庫(library),大部分為C的函數庫(libc)
          4:設備文件說明,通常在/dev下的文件
          5:配置文件或某些文件格式
          6:游戲(games)
          7:慣例與協議等,如Linux文件系統,網絡協議,ASCII code等說明
          8:系統管理員可用的管理命令
          9:跟kernel有關的文件
          

          實例

          我們輸入man ls,它會在最左上角顯示LS(1),在這里,LS 表示手冊名稱,而(1)表示該手冊位于第一節章,同樣,我們輸man ifconfig它會在最左上角顯示 IFCONFIG(8)。也可以這樣輸入命令:man [章節號] 手冊名稱。

          man 是按照手冊的章節號的順序進行搜索的,比如

          > man sleep
          

          只會顯示 sleep 命令的手冊, 如果想查看庫函數 sleep,就要輸入:

          > man 3 sleep
          

          原文鏈接:https://rumenz.com/rumenbiji/linux-man.html
          微信公眾號:入門小站

          • 回復【1001】獲取 linux常用命令速查手冊
          • 回復【10010】獲取 阿里云ECS運維Linux系統診斷
          • 回復【10012】獲取 Linux學習筆記【強悍總結值得一看】
          • 回復【10013】獲取 shell簡明教程

          們看到這個標題的時候,肯定在罵我,什么類這么厲害?使用率100%?其實我不是標題黨,本篇文章給大家介紹的就是JDK中所有類的父類——java.lang.Object,你說使用率不是100%,我想任何類都逃不掉吧。

          Object 類屬于 java.lang 包,此包下的所有類在使用時無需手動導入,系統會在程序編譯期間自動導入。Object 類是所有類的基類,當一個類沒有直接繼承某個類時,默認繼承Object類,也就是說任何類都直接或間接繼承此類,Object 類中能訪問的方法在所有類中都可以調用,下面我們會分別介紹Object 類中的所有方法。

          1、Object 類的結構圖

          Object.class類

          /*
           * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
           * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
           *
           */
          
          package java.lang;
          
          /**
           * Class {@code Object} is the root of the class hierarchy.
           * Every class has {@code Object} as a superclass. All objects,
           * including arrays, implement the methods of this class.
           *
           * @author  unascribed
           * @see     java.lang.Class
           * @since   JDK1.0
           */
          public class Object {
          
              private static native void registerNatives();
              static {
                  registerNatives();
              }
          
              public final native Class<?> getClass();
          
              public native int hashCode();
          
              public boolean equals(Object obj) {
                  return (this == obj);
              }
          
              protected native Object clone() throws CloneNotSupportedException;
              
              public String toString() {
                  return getClass().getName() + "@" + Integer.toHexString(hashCode());
              }
          
              public final native void notify();
              
              public final native void notifyAll();
              
              public final native void wait(long timeout) throws InterruptedException;
              
              public final void wait(long timeout, int nanos) throws InterruptedException {
                  if (timeout < 0) {
                      throw new IllegalArgumentException("timeout value is negative");
                  }
                  if (nanos < 0 || nanos > 999999) {
                      throw new IllegalArgumentException(
                              "nanosecond timeout value out of range");
                  }
                  if (nanos > 0) {
                      timeout++;
                  }
                  wait(timeout);
              }
              
              public final void wait() throws InterruptedException {
                  wait(0);
              }
              
              protected void finalize() throws Throwable { }
          }
          

          2、 為什么java.lang包下的類不需要手動導入?

          不知道大家注意到沒,我們在使用諸如Date類時,需要手動導入import java.util.Date,再比如使用File類時,也需要手動導入import java.io.File。但是我們在使用Object類,String 類,Integer類等不需要手動導入,而能直接使用,這是為什么呢?

          這里先告訴大家一個結論:使用 java.lang 包下的所有類,都不需要手動導入。

          另外我們介紹一下Java中的兩種導包形式,導包有兩種方法:

          ①、單類型導入(single-type-import),例如import java.util.Date

          ②、按需類型導入(type-import-on-demand),例如import java.util.*

          單類型導入比較好理解,我們編程所使用的各種工具默認都是按照單類型導包的,需要什么類便導入什么類,這種方式是導入指定的public類或者接口;

          按需類型導入,比如 import java.util.*,可能看到后面的 *,大家會以為是導入java.util包下的所有類,其實并不是這樣,我們根據名字按需導入要知道它是按照需求導入,并不是導入整個包下的所有類。

          Java編譯器會從啟動目錄(bootstrap),擴展目錄(extension)和用戶類路徑下去定位需要導入的類,而這些目錄僅僅是給出了類的頂層目錄,編譯器的類文件定位方法大致可以理解為如下公式:

          頂層路徑名 \ 包名 \ 文件名.class = 絕對路徑

          單類型導入我們知道包名和文件名,所以編譯器可以一次性查找定位到所要的類文件。按需類型導入則比較復雜,編譯器會把包名和文件名進行排列組合,然后對所有的可能性進行類文件查找定位。例如:

          package com;
          
          import java.io.*;
          
          import java.util.*;
          

          如果我們文件中使用到了 File 類,那么編譯器會根據如下幾個步驟來進行查找 File 類:

          ①、File       // File類屬于無名包,就是說File類沒有package語句,編譯器會首先搜索無名包

          ②、com.File     // File類屬于當前包,就是我們當前編譯類的包路徑

          ③、java.lang.File   //由于編譯器會自動導入java.lang包,所以也會從該包下查找

          ④、java.io.File

          ⑤、java.util.File

          ......

          需要注意的地方就是,編譯器找到java.io.File類之后并不會停止下一步的尋找,而要把所有的可能性都查找完以確定是否有類導入沖突。假設此時的頂層路徑有三個,那么編譯器就會進行3*5=15次查找。

          如果在查找完成后,編譯器發現了兩個同名的類,那么就會報錯。要刪除你不用的那個類,然后再編譯。

          所以我們可以得出這樣的結論:按需類型導入是絕對不會降低Java代碼的執行效率的,但會影響到Java代碼的編譯速度。所以我們在編碼時最好是使用單類型導入,這樣不僅能提高編譯速度,也能避免命名沖突。

          講清楚Java的兩種導包類型了,我們再回到為什么可以直接使用 Object 類,看到上面查找類文件的第③步,編譯器會自動導入 java.lang 包,那么當然我們能直接使用了。至于原因,因為用的多,提前加載了,省資源。

          3、類構造器

          我們知道類構造器是創建Java對象的途徑之一,通過new 關鍵字調用構造器完成對象的實例化,還能通過構造器對對象進行相應的初始化。一個類必須要有一個構造器的存在,如果沒有顯示聲明,那么系統會默認創造一個無參構造器,在JDK的Object類源碼中,是看不到構造器的,系統會自動添加一個無參構造器。我們可以通過:

          Object obj = new Object();構造一個Object類的對象。

          4、equals 方法

          通常很多面試題都會問 equals() 方法和 == 運算符的區別,== 運算符用于比較基本類型的值是否相同,或者比較兩個對象的引用是否相等,而 equals 用于比較兩個對象是否相等,這樣說可能比較寬泛,兩個對象如何才是相等的呢?這個標尺該如何定?我們可以看看 Object 類中的equals 方法:

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

          可以看到,在 Object 類中,== 運算符和 equals 方法是等價的,都是比較兩個對象的引用是否相等,從另一方面來講,如果兩個對象的引用相等,那么這兩個對象一定是相等的。對于我們自定義的一個對象,如果不重寫 equals 方法,那么在比較對象的時候就是調用 Object 類的 equals 方法,也就是用 == 運算符比較兩個對象。我們可以看看 String 類中的重寫的 equals 方法:

          public boolean equals(Object anObject) {
                  if (this == anObject) {
                      return true;
                  }
                  if (anObject instanceof String) {
                      String anotherString = (String)anObject;
                      int n = value.length;
                      if (n == anotherString.value.length) {
                          char v1[] = value;
                          char v2[] = anotherString.value;
                          int i = 0;
                          while (n-- != 0) {
                              if (v1[i] != v2[i])
                                  return false;
                              i++;
                          }
                          return true;
                      }
                  }
                  return false;
              }
          

          String 是引用類型,比較時不能比較引用是否相等,重點是字符串的內容是否相等。所以 String 類定義兩個對象相等的標準是字符串內容都相同。

          在Java規范中,對 equals 方法的使用必須遵循以下幾個原則:

          ①、自反性:對于任何非空引用值 x,x.equals(x) 都應返回 true。

          ②、對稱性:對于任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。

          ③、傳遞性:對于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 應返回 true。

          ④、一致性:對于任何非空引用值 x 和 y,多次調用 x.equals(y) 始終返回 true 或始終返回 false,前提是對象上 equals 比較中所用的信息沒有被修改

          ⑤、對于任何非空引用值 x,x.equals(null) 都應返回 false。

          下面我們自定義一個 Person 類,然后重寫其equals 方法,比較兩個 Person 對象:

          package com.ys.bean;
          /**
           * Create by vae
           */
          public class Person {
              private String pname;
              private int page;
          
              public Person(){}
          
              public Person(String pname,int page){
                  this.pname = pname;
                  this.page = page;
              }
              public int getPage() {
                  return page;
              }
          
              public void setPage(int page) {
                  this.page = page;
              }
          
              public String getPname() {
                  return pname;
              }
          
              public void setPname(String pname) {
                  this.pname = pname;
              }
              @Override
              public boolean equals(Object obj) {
                  if(this == obj){//引用相等那么兩個對象當然相等
                      return true;
                  }
                  if(obj == null || !(obj instanceof  Person)){//對象為空或者不是Person類的實例
                      return false;
                  }
                  Person otherPerson = (Person)obj;
                  if(otherPerson.getPname().equals(this.getPname()) && otherPerson.getPage()==this.getPage()){
                      return true;
                  }
                  return false;
              }
          
              public static void main(String[] args) {
                  Person p1 = new Person("Tom",21);
                  Person p2 = new Person("Marry",20);
                  System.out.println(p1==p2);//false
                  System.out.println(p1.equals(p2));//false
          
                  Person p3 = new Person("Tom",21);
                  System.out.println(p1.equals(p3));//true
              }
          
          }
          

          通過重寫 equals 方法,我們自定義兩個對象相等的標尺為Person對象的兩個屬性都相等,則對象相等,否則不相等。如果不重寫 equals 方法,那么始終是調用 Object 類的equals 方法,也就是用 == 比較兩個對象在棧內存中的引用地址是否相等。

          這時候有個Person 類的子類 Man,也重寫了 equals 方法:

          package com.ys.bean;
          /**
           * Create by vae
           */
          public class Man extends Person{
              private String sex;
          
              public Man(String pname,int page,String sex){
                  super(pname,page);
                  this.sex = sex;
              }
              @Override
              public boolean equals(Object obj) {
                  if(!super.equals(obj)){
                      return false;
                  }
                  if(obj == null || !(obj instanceof  Man)){//對象為空或者不是Person類的實例
                      return false;
                  }
                  Man man = (Man) obj;
                  return sex.equals(man.sex);
              }
          
              public static void main(String[] args) {
                  Person p = new Person("Tom",22);
                  Man m = new Man("Tom",22,"男");
          
                  System.out.println(p.equals(m));//true
                  System.out.println(m.equals(p));//false
              }
          }
          

          通過打印結果我們發現 person.equals(man)得到的結果是 true,而man.equals(person)得到的結果卻是false,這顯然是不正確的。

          問題出現在 instanceof 關鍵字上,關于 instanceof 關鍵字的用法,可以參考我的這篇文章:http://www.cnblogs.com/ysocean/p/8486500.html

          Man 是 Person 的子類,person instanceof Man 結果當然是false。這違反了我們上面說的對稱性。

          實際上用 instanceof 關鍵字是做不到對稱性的要求的。這里推薦做法是用 getClass()方法取代 instanceof 運算符。getClass() 關鍵字也是 Object 類中的一個方法,作用是返回一個對象的運行時類,下面我們會詳細講解。

          那么 Person 類中的 equals 方法為

          public boolean equals(Object obj) {
                  if(this == obj){//引用相等那么兩個對象當然相等
                      return true;
                  }
                  if(obj == null || (getClass() != obj.getClass())){//對象為空或者不是Person類的實例
                      return false;
                  }
                  Person otherPerson = (Person)obj;
                  if(otherPerson.getPname().equals(this.getPname()) && otherPerson.getPage()==this.getPage()){
                      return true;
                  }
                  return false;
              }
          

          打印結果 person.equals(man)得到的結果是 false,man.equals(person)得到的結果也是false,滿足對稱性。

          注意:使用 getClass 不是絕對的,要根據情況而定,畢竟定義對象是否相等的標準是由程序員自己定義的。而且使用 getClass 不符合多態的定義,比如 AbstractSet 抽象類,它有兩個子類 TreeSet 和 HashSet,他們分別使用不同的算法實現查找集合的操作,但無論集合采用哪種方式實現,都需要擁有對兩個集合進行比較的功能,如果使用 getClass 實現equals方法的重寫,那么就不能在兩個不同子類的對象進行相等的比較。而且集合類比較特殊,其子類是不需要自定義相等的概念的。

          所以什么時候使用 instanceof 運算符,什么時候使用 getClass() 有如下建議:

          ①、如果子類能夠擁有自己的相等概念,則對稱性需求將強制采用 getClass 進行檢測。

          ②、如果有超類決定相等的概念,那么就可以使用 instanceof 進行檢測,這樣可以在不同的子類的對象之間進行相等的比較。

          下面給出一個完美的 equals 方法的建議:

          1、顯示參數命名為 otherObject,稍后會將它轉換成另一個叫做 other 的變量。

          2、判斷比較的兩個對象引用是否相等,如果引用相等那么表示是同一個對象,那么當然相等

          3、如果 otherObject 為 null,直接返回false,表示不相等

          4、比較 this 和 otherObject 是否是同一個類:如果 equals 的語義在每個子類中有所改變,就使用 getClass 檢測;如果所有的子類都有統一的定義,那么使用 instanceof 檢測

          5、將 otherObject 轉換成對應類的類型變量

          6、最后對對象的屬性進行比較。使用 == 比較基本類型,使用 equals 比較對象。如果都相等則返回true,否則返回false。注意如果是在子類中定義equals,則要包含 super.equals(other)

          下面我們給出 Person 類中完整的 equals 方法的書寫:

          @Override
              public boolean equals(Object otherObject) {
                  //1、判斷比較的兩個對象引用是否相等,如果引用相等那么表示是同一個對象,那么當然相等
                  if(this == otherObject){
                      return true;
                  }
                  //2、如果 otherObject 為 null,直接返回false,表示不相等
                  if(otherObject == null ){//對象為空或者不是Person類的實例
                      return false;
                  }
                  //3、比較 this 和 otherObject 是否是同一個類(注意下面兩個只能使用一種)
                  //3.1:如果 equals 的語義在每個子類中所有改變,就使用 getClass 檢測
                  if(this.getClass() != otherObject.getClass()){
                      return false;
                  }
                  //3.2:如果所有的子類都有統一的定義,那么使用 instanceof 檢測
                  if(!(otherObject instanceof Person)){
                      return false;
                  }
          
                  //4、將 otherObject 轉換成對應的類類型變量
                  Person other = (Person) otherObject;
          
                  //5、最后對對象的屬性進行比較。使用 == 比較基本類型,使用 equals 比較對象。如果都相等則返回true,否則返回false
                  //   使用 Objects 工具類的 equals 方法防止比較的兩個對象有一個為 null而報錯,因為 null.equals() 是會拋異常的
                  return Objects.equals(this.pname,other.pname) && this.page == other.page;
          
                  //6、注意如果是在子類中定義equals,則要包含 super.equals(other)
                  //return super.equals(other) && Objects.equals(this.pname,other.pname) && this.page == other.page;
          
              }
          

          請注意,無論何時重寫此方法,通常都必須重寫hashCode方法,以維護hashCode方法的一般約定,該方法聲明相等對象必須具有相同的哈希代碼。hashCode 也是 Object 類中的方法,后面會詳細講解

          5、getClass 方法

          上面我們在介紹 equals 方法時,介紹如果 equals 的語義在每個子類中有所改變,那么使用 getClass 檢測,為什么這樣說呢?

          getClass()在 Object 類中如下,作用是返回對象的運行時類。

          public final native Class<?> getClass();
          

          這是一個用 native 關鍵字修飾的方法,關于 native 關鍵字的詳細介紹如下:http://www.cnblogs.com/ysocean/p/8476933.html

          這里我們要知道用 native 修飾的方法我們不用考慮,由操作系統幫我們實現,該方法的作用是返回一個對象的運行時類,通過這個類對象我們可以獲取該運行時類的相關屬性和方法。也就是Java中的反射,各種通用的框架都是利用反射來實現的,這里我們不做詳細的描述。

          這里詳細的介紹 getClass 方法返回的是一個對象的運行時類對象,這該怎么理解呢?Java中還有一種這樣的用法,通過 類名.class 獲取這個類的類對象 ,這兩種用法有什么區別呢?

          父類:Parent.class

          public class Parent {}
          

          子類:Son.class

          public class Son extends Parent{}
          

          測試:

          @Test
          public void testClass(){
              Parent p = new Son();
              System.out.println(p.getClass());
              System.out.println(Parent.class);
          }
          

          打印結果:

          結論:class 是一個類的屬性,能獲取該類編譯時的類對象,而 getClass() 是一個類的方法,它是獲取該類運行時的類對象。

          還有一個需要大家注意的是,雖然Object類中getClass() 方法聲明是:public final native Class getClass();返回的是一個 Class,但是如下是能通過編譯的:

          Class<? extends String> c = "".getClass();
          

          也就是說類型為T的變量getClass方法的返回值類型其實是Class而非getClass方法聲明中的Class。

          這在官方文檔中也有說明:https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--

          6、hashCode 方法

          hashCode 在 Object 類中定義如下:

          public native int hashCode();
          

          這也是一個用 native 聲明的本地方法,作用是返回對象的散列碼,是 int 類型的數值。

          那么這個方法存在的意義是什么呢?

          我們知道在Java 中有幾種集合類,比如 List、Set,還有 Map,List集合一般是存放的元素是有序可重復的,Set 存放的元素則是無序不可重復的,而 Map 集合存放的是鍵值對。

          前面我們說過判斷一個元素是否相等可以通過 equals 方法,每增加一個元素,那么我們就通過 equals 方法判斷集合中的每一個元素是否重復,但是如果集合中有10000個元素了,當我們新加入一個元素時,那就需要進行10000次equals方法的調用,這顯然效率很低。

          于是,Java 的集合設計者就采用了 哈希表 來實現。關于哈希表的數據結構我有過介紹。哈希算法也稱為散列算法,是將數據依特定算法產生的結果直接指定到一個地址上。這個結果就是由 hashCode 方法產生。這樣一來,當集合要添加新的元素時,先調用這個元素的 hashCode 方法,就一下子能定位到它應該放置的物理位置上。

          ①、如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;

          ②、如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了;

          ③、不相同的話,也就是發生了Hash key相同導致沖突的情況,那么就在這個Hash key的地方產生一個鏈表,將所有產生相同HashCode的對象放到這個單鏈表上去,串在一起(很少出現)。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。  

          這里有 A,B,C,D四個對象,分別通過 hashCode 方法產生了三個值,注意 A 和 B 對象調用 hashCode 產生的值是相同的,即 A.hashCode() = B.hashCode() = 0x001,發生了哈希沖突,這時候由于最先是插入了 A,在插入的B的時候,我們發現 B 是要插入到 A 所在的位置,而 A 已經插入了,這時候就通過調用 equals 方法判斷 A 和 B 是否相同,如果相同就不插入 B,如果不同則將 B 插入到 A 后面的位置。所以對于 equals 方法和 hashCode 方法有如下要求:

          一、hashCode 要求   

          ①、在程序運行時期間,只要對象的(字段的)變化不會影響equals方法的決策結果,那么,在這個期間,無論調用多少次hashCode,都必須返回同一個散列碼。

          ②、通過equals調用返回true 的2個對象的hashCode一定一樣。

          ③、通過equasl返回false 的2個對象的散列碼不需要不同,也就是他們的hashCode方法的返回值允許出現相同的情況。

          因此我們可以得到如下推論:

          兩個對象相等,其 hashCode 一定相同;

          兩個對象不相等,其 hashCode 有可能相同;

          hashCode 相同的兩個對象,不一定相等;

          hashCode 不相同的兩個對象,一定不相等;

          這四個推論通過上圖可以更好地理解。

          可能會有人疑問,對于不能重復的集合,為什么不直接通過 hashCode 對于每個元素都產生唯一的值,如果重復就是相同的值,這樣不就不需要調用 equals 方法來判斷是否相同了嗎?  實際上對于元素不是很多的情況下,直接通過 hashCode 產生唯一的索引值,通過這個索引值能直接找到元素,而且還能判斷是否相同。比如數據庫存儲的數據,ID 是有序排列的,我們能通過 ID 直接找到某個元素,如果新插入的元素 ID 已經有了,那就表示是重復數據,這是很完美的辦法。但現實是存儲的元素很難有這樣的 ID 關鍵字,也就很難這種實現 hashCode 的唯一算法,再者就算能實現,但是產生的 hashCode 碼是非常大的,這會大的超過 Java 所能表示的范圍,很占內存空間,所以也是不予考慮的。

          二、hashCode 編寫指導:  

          ①、不同對象的hash碼應該盡量不同,避免hash沖突,也就是算法獲得的元素要盡量均勻分布。

          ②、hash 值是一個 int 類型,在Java中占用 4 個字節,也就是 2的32 次方,要避免溢出。

          在 JDK 的 Integer類,Float 類,String 類等都重寫了 hashCode 方法,我們自定義對象也可以參考這些類來寫。

          下面是 JDK String 類的hashCode 源碼:

          public int hashCode() {
                  int h = hash;
                  if (h == 0 && value.length > 0) {
                      char val[] = value;
          
                      for (int i = 0; i < value.length; i++) {
                          h = 31 * h + val[i];
                      }
                      hash = h;
                  }
                  return h;
              }
          

          再次提醒大家,對于 Map 集合,我們可以選取Java中的基本類型,還有引用類型 String 作為 key,因為它們都按照規范重寫了 equals 方法和 hashCode 方法。但是如果你用自定義對象作為 key,那么一定要覆寫 equals 方法和 hashCode 方法,不然會有意想不到的錯誤產生。

          7、toString 方法

          該方法在 JDK 的源碼如下:

              public String toString() {
                  return getClass().getName() + "@" + Integer.toHexString(hashCode());
              }
          

          getClass().getName()是返回對象的全類名(包含包名),Integer.toHexString(hashCode()) 是以16進制無符號整數形式返回此哈希碼的字符串表示形式。

          打印某個對象時,默認是調用 toString 方法,比如 System.out.println(person),等價于 System.out.println(person.toString())

          8、notify()/notifyAll()/wait()

          這是用于多線程之間的通信方法,在后面講解多線程會詳細描述,這里就不做講解了。

          protected void finalize() throws Throwable { }
          

          該方法用于垃圾回收,一般由 JVM 自動調用,一般不需要程序員去手動調用該方法。后面再講解 JVM 的時候會詳細展開描述。

          10、registerNatives 方法

          該方法在 Object 類中定義如下:

          private static native void registerNatives();
          

          這是一個本地方法,在 native 介紹 中我們知道一個類定義了本地方法后,想要調用操作系統的實現,必須還要裝載本地庫,但是我們發現在 Object.class 類中具有很多本地方法,但是卻沒有看到本地庫的載入代碼。而且這是用 private 關鍵字聲明的,在類外面根本調用不了,我們接著往下看關于這個方法的類似源碼:

              static {
                  registerNatives();
              }
          

          看到上面的代碼,這就明白了吧。靜態代碼塊就是一個類在初始化過程中必定會執行的內容,所以在類加載的時候是會執行該方法的,通過該方法來注冊本地方法。

          11、小結

          好了,這就是JDK中java.lang.Object類的源碼解析。指北君后續的文章會給大家介紹JDK的各種源碼,讓大家吃透JDK,另外還有各種工作趣聞,面試寶典。

          我是指北君,操千曲而后曉聲,觀千劍而后識器。感謝各位人才的:點贊、收藏和評論,我們下期更精彩!

          原文鏈接:https://mp.weixin.qq.com/s/vIiaPv-qaCLgCZy5gpJb9Q


          主站蜘蛛池模板: 精品国产日韩亚洲一区| AV鲁丝一区鲁丝二区鲁丝三区| 精品国产一区二区三区不卡| 国产福利电影一区二区三区久久老子无码午夜伦不 | 天堂资源中文最新版在线一区| 海角国精产品一区一区三区糖心| 午夜视频一区二区三区| 精品无码人妻一区二区三区不卡 | 中日韩精品无码一区二区三区| 亚洲无码一区二区三区| 国产一区二区三区在线| 中文字幕一区二区日产乱码| 无码日韩AV一区二区三区| 免费观看一区二区三区| 相泽南亚洲一区二区在线播放| 亚洲爽爽一区二区三区| 国产乱人伦精品一区二区在线观看 | 亚洲AⅤ无码一区二区三区在线 | 国产精品亚洲综合一区在线观看 | 无码人妻啪啪一区二区| 亚洲无线码在线一区观看| 国产精品亚洲不卡一区二区三区 | 亚洲无线码在线一区观看| 国产人妖视频一区在线观看| 中文字幕一区二区三区乱码| 久久久久女教师免费一区| 无码人妻一区二区三区免费视频| 福利电影一区二区| 91麻豆精品国产自产在线观看一区| 无码人妻一区二区三区免费视频 | 亚洲AV美女一区二区三区| 亚洲日本一区二区三区在线不卡 | 日韩精品一区二区三区中文 | 立川理惠在线播放一区| 无码喷水一区二区浪潮AV| 国产在线观看一区二区三区精品 | 国产福利电影一区二区三区,日韩伦理电影在线福 | 国产乱码精品一区二区三区麻豆| 国产一区在线视频观看| 成人区精品一区二区不卡| 亚洲国产日韩在线一区|