Chrome 開始在共用螢幕畫面時將瀏覽器通知靜音處理,避免個人隱私被看光光_網頁設計公司

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

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

從疫情爆發之後,遠端工作與虛擬會議已經成為工作與生活中的常態,而在會議中當然不只有談話,有些更正是的視訊會議裡面你還必須共享電腦螢幕畫面上,以進行操作與成果的展示等,如果有這樣的需求,相信大家會想方設法來讓自己的桌面看起來更乾淨美觀,但總會有些無法控制的通知跳出來,被全部看光光好尷尬呀!Google 現在為了這些不受控的事情,為 Chrome 導入了一個小卻很重要的功能。

Chrome 開始在共用螢幕畫面時將瀏覽器通知靜音處理,避免個人隱私被看光光

任何參加過視訊會議或進行線上直播展示的人可能都遇過,當你的展示一切都很順利,眼看就可以完美收官了,直到你的瀏覽器分頁之一收到通知,大咧咧地彈出在所有人面前「雅俗共賞」,這一情況不僅讓與會人士分心,當訊息內容比較私密、個人的時候,還會成為隱私攤在所有人眼前的問題。

當然,你可以直接選擇禁用瀏覽器通知,但這通常需要進行很多步驟來設定,而且還要記得在共用螢幕之前記得去設定,在結束共用之後再重新開啟通知,不過光是螢幕共用展示的身心準備已經很緊張,大多數人可能並不記得採取這些預防措施。Chrome 瀏覽器現在將幫你拾遺補漏,當你開始共用螢幕時,它會通知你接下來將自動令瀏覽器進入靜音狀態,且在你的螢幕共用時隱藏通知內容。當你結束共用螢幕後,所有之前被靜音的通知都將會在後續顯示出來。

通知靜音功能不僅適用於 Google 自家應用程式(如 Gmail 或 Google Chat 等),也適用於第三方網站,最重要的是此功能面向所有人推出,無論你是商務企業方案訂閱戶或是個人 Google 帳戶都能擁有,就藏在 Chrome 88 版中。

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

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

◎資料來源:9to5Google、SlashGear

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

國外設計師分享 iPhone SE 2021 概念圖,無邊框與挖孔螢幕、側邊電源鍵指紋解鎖_網頁設計

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

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

雖然去年 Apple 已經更新過 iPhone SE 2020,就產品週期來看今年應該不太可以有新款,但近期又有一支 iPhone SE Plus 的傳言傳出,如果真有 Plus 版本,那 iPhone SE 2021 也不無可能,最近國外就有設計師製作出一組 iPhone SE 2021 的概念圖,不得不說看起來還蠻正點的,下面分享給大家。

國外設計師分享 iPhone SE 2021 概念圖

Svetapple 近日分享一組 iPhone SE 2021 的概念設計圖,其靈感是來自 iPhone 12 mini,尺寸大致相同,不過螢幕部分改成挖孔面板,變成只有相機鏡頭,意味著現行的 iPhone SE 2020 正面上下黑邊都會消失:

Svetapple 也提到,iPhone SE 2021 不太可能會有 Face ID 臉部解鎖,因為這位將成本提高,售價變更貴,不符合這支的定位。至於原有的 Touch ID 指紋解鎖則移到側邊電源鍵上,就跟 iPad Air(第四代一樣)。

尺寸為 5.4 吋,改搭載 OLED 螢幕,顯示畫面將更加漂亮。主相機依舊只有一顆鏡頭,採 1,200 萬畫素與支援人像模式等功能,

硬體方面可能會搭載 A14 處理器,內建 4GB RAM,也提供 64GB、128GB 與 256GB 三種容量選擇,下圖為完整概念規格:

整體來看,iPhone SE 2021 採用這設計看起來相當合理,再加上外界也曾謠傳因銷售不如預期,下一代 iPhone mini 搞不好會被取消,如果真是這樣,iPhone SE 2021 就有機會取代 iPhone mini,規格當然多少會提升。

不過面板改成挖孔之後,成本一定會比現行的 iPhone SE 2020 還高,意味著售價會變更貴,Svetapple 也預測變成 499 美元起。

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

下方是上週 Apple Lab 分享的 iPhone SE Plus 傳言:

iPhone SE Plus
– Display: 6.1″ (IPS)
– Chip: Apple A14 (A13) Bionic
– Camera: Main: 12Mp (iSight), Sefie 7Mp (FaceTime HD)
– Features: 6 Portrait Light effect / OIS / Smart HDR 3 / IP67 / Color (Black / Red / White?)
– Security: TouchID in Home Button
– Price: ≈499$ / ≈589€ pic.twitter.com/wQkz19QYoL

— Apple Lab (@aaple_lab) January 19, 2021

資料來源:Svetapple

BlackSight:讓老 iPhone 也能支援夜景模式的相機 App

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

微軟黑科技幫你跟亡者聊天?新專利將能讓AI 學會已故親人的說話口氣與外貌_貨運

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

有句話這麼說:「世界上最遙遠的距離,不是生與死,而是我就站在你面前,你卻不知道我愛你」。然而,生離死別的痛苦仍然不亞於「你卻不知道我愛你」的痛苦。不論是親人還是愛人,死亡強硬的切開了彼此之間的距離與情感。台灣民間信仰中,有一種請所謂的仙姑、靈姑尋找已逝者的亡魂,並藉由上身這個儀式來讓亡魂藉由仙姑,與在世的親人交談的特殊宗教服務。有意思的是,許多科技公司也正在試著讓 AI 也能達到類似的效果。不過他們並非真的請亡魂來上「電腦」的身。以微軟最近的專利來說,就是利用 AI 去學習已故親人說話語氣、用詞用語等資料,並透過分析親人的肖像來製作 3D 模型。如此一來,一個能在電腦中與人對話,又有著與親人相似外貌的聊天機器人就誕生了:

▲微軟的專利居然有與亡者交談的部分,真的是太奇葩了(圖片來源)

微軟不是第一家想做「亡者聊天機器人」的公司,但不過在微軟之前提出類似想法的公司規模都相對較小,因此當微軟這方面的專利技術被嗅覺靈敏的媒體挖掘出來時,才讓人發現原來軟體巨頭不光只是想做個像 Cortana 那樣的語音助理而已。憑微軟的規模與財力,有心要做的話理論上是很容易實現的。

讓 AI 學習一切親人的相關資料,就能真的「仿生」他的音容笑貌

言歸正傳,這項專利是由微軟公司的 Dustin Abramson 和 Joseph Johnson jr. 兩位研究者於 2017 年註冊的。根據專利的敘述,他們將設計一個可以學習亡者生前所發表的社交貼文、語音資料、電子資料與個人圖像等資料的 AI,這個 AI 將能依照資料的完整程度,模仿出一個幾乎接近亡者在生時的模樣、語氣的聊天機器人。根據技術的成熟度,可能達到旁人不覺得說話的是個機器的程度:

▲這設定其實很多科幻作品都有類似的橋段,例如漫畫作品「人形電腦天使心(Chobits)」中,就有為了思念親人而將人形電腦製作成親人面貌的設定(圖片來源)

這個技術或許讓人想起很多科幻影劇或小說之類的內容,畢竟類似的題材相信好萊塢拍得夠多了。如果按照這個專利來看,人與生化人之間的差異性或許會進一步的縮小到難以察覺差異的程度。不過在這個技術正式實體化前,或許這些論調都只是杞人憂天:

▲即便是電腦模擬出來的,能跟已故的親人筆談一下也能夠撫慰人心(圖片來源)

▲肯伊威斯特曾在去年買下岳父生前樣貌的全息投影作為生日禮物送給妻子金卡戴珊,這或許是這項專利可能的呈現形式(圖片翻攝自 Twitter)

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

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

對於一些平常會找仙姑、巫醫之類的民俗宗教人士來跟陰間親人溝通或問些事情的人來說,這項技術或許就是用現代科學創造出一個思想邏輯上幾乎與本人差不多的生化人。這種生化人不太可能有靈魂上身,但一樣可以對它「問事」,某種意義上甚至可以當作當事人思想的一種參考。

消息來源:Gizmodo、USPTO

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔_網頁設計公司

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

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

好了好了,別再說近 20 萬 Alpha 1 螢幕不能翻轉解析度又低是哪招。秉持著 One Sony 精神,Xperia 立馬就來了個同集團最強手機與相機的強強結合 — 如同預測的那樣,Xperia PRO 在具備 8K 錄影機能的 A1 發表時也隨之正式推出。將可透過 HDMI 外接的方式,成為史上最強的 4K HDR OLED 監視螢幕 — 嗯… 再加上 5G mmWave 連線應該算吧?不然… 你有看過搭載 3 主相機 + 3D iTOF 的監視器嗎!繼續閱讀要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔報導內文。

▲圖片來源:

要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔

全面迎擊對手挑戰,帶來 8K 30fps 與 4K 120fps 錄影機能以及 50MP 高畫質、30fps 高速連拍,以「One」之名成為 Alpha 全片幅無反最高階存在的 A1。想不到還是承襲了 Sony 無反螢幕規格總是稍微弱了些的 DNA,甚至也沒有配上 A7S III 的全翻轉螢幕。實在是讓你有點失望?

其實 Sony 早早在去年就宣佈了配合 A1 的解決方案,將為專業而生的旗艦手機 Xperia PRO 在專業相機的發表會場合正式推出,宣布了上市資訊與相關規格。

Xperia PRO 搭載有支援超越 PCI-P3 廣色域,並與專業級 HDR 監控螢幕 Sony BVM-X300 採相同 gamut 係數的 6.5 吋 4K HDR OLED 螢幕。有望成為專業攝錄工作流程中相當輕便但強大的工具。在這次 Alpha 1 全幅無反機皇的發表會裡,Sony 也釋出其 US$2,500 的售價(!)並確認將正式在海外開賣。

既然這是台換算近 7 萬台幣的「手機」,大家應該完全可以感受到它的確並不是為一般人而來的產品。近年致力於為創作者打造核心體驗的 Sony 旗艦手機,現在,純粹為專業而生的 Xperia PRO 也進化登場。

之所以敢訂出這樣專業級的售價,Xperia PRO 自然有著專業用戶會想要買單的規格。支援觸控放大的 4K 60fps HDR 監視螢幕的用途應該不用再特別說了。它不僅可以透過 micro HDMI 外接,輸入影像進行最高 131Mbps 的串流直播,並能以 5G 毫米波搭配四組 360 度全向天線的強大連線規格全力保證通訊的穩定。

內建 3.5mm 耳機孔、雙前置揚聲器也支援杜比全景聲的它,不僅可以進行即時的影音回放,也能直接做為檔案傳輸中心,即時將內容透過 5G 傳輸至 FTP 伺服器。配合 Alpha 1 更進階的耐候規格,Xperia PRO 也擁有 IP65/68 的耐候能力,加上看起來相當強壯的機身設計,想必未來應該可以在不少專業製片領域看到它的蹤跡才是。

本篇圖片 / 引用來源

延伸閱讀:

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

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

能錄 8K 的 Sony Alpha 1 全幅無反全能機皇正式發表

M1 MacBook Air 開箱體驗:最驚喜的不變

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

顯卡持續缺貨,中國加密貨幣礦工現在看上 RTX 3060 遊戲筆電, 挖礦效率意外的高_潭子電動車

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

加密貨幣價格 2017 年崩盤之後,過去三年挖礦熱潮就大幅退燒,甚至還出現不少礦機被丟進垃圾場的照片。隨著去年比特幣、以太幣等加密貨幣再度大漲,AMD 與 NVIDA 桌機顯卡又開始出現短缺的情形,而且是過了半年還一樣,為此中國礦工開始將目標轉向 RTX 3000 系列遊戲筆電,最近就有人分享 RTX 3060 的挖礦測試,效率還相當不錯,看來在桌顯缺貨狀況尚未改善前,新款 RTX 3000 系列筆電搞不好也要面臨短缺現象了。

顯卡持續缺貨,中國加密貨幣礦工現在看上 RTX 3060 遊戲筆電

最近一位 JJJJKQ 中國網友於百度貼吧分享他實測 RTX 3060 Max-P 遊戲筆電的挖礦效率截圖,從數據來看,這顆晶片在挖以太幣(ETH)時效率可說相當不錯,GPU 算力為 48.99MH/s,溫度在 66 度上下。另外從配置來看,他有超頻 RTX 3060 Max-P,並不是以基礎效能下去挖礦:

GPU-Z 顯示,GPU 時脈為 1567.0MHz,記憶體時脈也來到 2125.2MHz,功耗為 104.7W:

就規格來說,RTX 3060 Max-P 行動顯示晶片跟 RTX 3060 桌顯比,TDP 雖然比較低(行動版 80W~130W、桌機 170W),不過 CUDA 核心 RTX 3060 Max-P 較多,來到 3,840 個,RTX 3060 桌顯則是 3,584 個,這也是為什麼拿來挖以太幣也能有不錯表現。

另外目前他測試的 RTX 3060 Max-P 功耗被限制在 104.7W,意味著如果提升到最高的 130W,挖礦效率應該還會更好。

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

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

RTX 3060 預計在 2 月下旬上市,還有半個多月的時間,因此在這之前,RTX 3000 系列筆電搞不好會先被礦工們掃購,導致缺貨的狀況出現,而且這討論串的回應中也有人提到,已經有 RTX 3060 筆電開始漲價了。

話說回來,筆電還是不太適合這樣長時間高速運轉,很容易導致內部硬體過熱燒壞。

資料來源:中國百度貼吧

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

Google 在台灣成立硬體研發基地,規模僅次於美國總部_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

Google 今天(1/27)宣布最新辦公室正式啟用,選址於台北遠東通訊園區(TPark)內,並且預計會在 2023 年於園區內再添另一座辦公室。此次 Google 的新辦公室也是除美國總部之外,全球首座且規模最大的硬體研發基地,更會是整合 Google 自家強大 AI、軟硬體技術的全球創新樞紐核心。

Google 在台灣成立硬體研發基地,規模僅次於美國總部

台灣在 Google 全球佈局的願景中,不管在產品研發、網路基礎建設還是市場營運,一直在其中扮演著重要角色。在過去 5 年以來,Google 在台灣的正職員工人數已成長 10 倍,辦公室據點橫跨 6 個縣市。為了因應成長需求,落實多元包容理念,Google 台灣將在今年擴大人才招募與實習計劃,並推出針對女性、弱勢族群等相關的職涯發展活動,預計將培訓與徵才機會拓展至更多校園和職能領域。

Google 硬體副總裁彭昱鈞表示:「很開心台灣已躍升為 Google 的主要策略據點,許多像是 Pixel 手機、Nest 智慧裝置、Chromebook 筆記型電腦、穿戴式裝置、Chromecast 串流播放器等全球性產品的軟硬體研發,均由 Google 台灣團隊的高度參與、甚至主導進行。我們期待能在台灣持續深耕發展,並且歡迎更多來自本地和海外的人才加入 Google 台灣。 」

Google 今年持續在台灣擴大招募規模。為了吸引各種專業領域與多元背景的人才,Google 將在台灣展開多項行動,與校園與產業人士進行更多交流,提供職涯發展的機會,其中包括:

  • 新增多種實習職缺:
    除原先軟硬體工程、資料中心、銷售業務、行銷等領域的實習計劃,今年將首度新增製造工程、Google Cloud 雲端服務、技術專案管理等實習機會。
  • 推廣多元與包容的工作環境:
    Google 在 2019 年推出了針對弱勢殘障族群的獎助學金 「Google Taiwan Student Associate 專案」,目前已獲良好迴響。今年 Google 將擴大該專案範圍,並提高獎學金申請名額,幫助弱勢學生提升職場技能,累積更多實際工作經驗。此外,Google 也延續過去針對鼓勵女性學習資訊科學、進入科技產業的努力,在今年持續透過相關講座與交流活動推廣倡議。
  • 擴展線上校園徵才:
    Google 預計在 2021 年底前至 50 所台灣大專院校進行線上校園徵才活動,尋找擁有潛力的學生。同時 Google 也將深化與大學教師的連結,進行更多科技創新思維的交流,帶動更多產學雙向刺激。
  • 提供免費線上課程:
    Google 將在台灣提供更多與軟硬體及雲端技術相關的免費線上課程,協助潛在人才獲取實用技能,做好未來投入相關領域工作的準備。

Google 台灣於 2006 年正式成立,今年是 Google 在台灣營運的 15 周年, HTC 手機研發部門正式加入 Google 台灣團隊也已屆滿 3 週年。近年來 Google 台灣已發展為亞洲最大的研發基地之一,因此在人才招募、辦公空間、研發與基礎建設的需求均大幅提升。全新的辦公園區設有各類型的實驗室與測試設施,讓 Google 台灣團隊更有效率地進行各種產品的技術開發與製造流程,此外新辦公室也設置了幫助外部訪客瞭解 Google AI 與軟硬體體驗的產品情境展示區。

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

Google 承諾在台灣長期發展,並已為擴大規模做好充足準備。除了確保 Google 在台灣的營運能嘉惠當地用戶和合作夥伴,Google 更將台灣視為技術研發與基礎建設的全球樞紐,以台灣為核心,在此打造出創新、便利、使全球使用者受惠的產品與服務。

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

真實世界的蒙娜麗莎?藝術家用AI技術「重現」經典名畫 體現現實與想像的差距_台中搬家

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

先前曾使用AI StyleGAN技術,完美呈現「真實版」經典動畫角色的美國藝術家Nathan Shipley,最近又出招了!他這次同樣是透過AI StyleGAN技術來進行創作,竟然將一些經典的人物肖像畫做出真實版的模樣,其中包含大家耳熟能詳的蒙娜麗莎。

↑李奧納多·達文西所繪製的《蒙娜麗莎》。

在vfx和動態圖形領域有著豐富經驗的Nathan,先前就曾使用AI StyleGAN技術,透過Pixel2Style2Pixel(pSp)技術轉換框架,將許多動漫作品中知名的經典角色成功「真人化」,其中包含了皮克斯電影《超人特攻隊》與《天外奇蹟》中的角色,由於他所做出來的成果實在太過逼真,在國外引起不小的討論。

 

而他近日再度嘗試透過AI StyleGAN技術,將許多經典的人物肖像畫進行「複刻」,其中包含了大家耳熟能詳、由李奧納多·達文西所繪製的《蒙娜麗莎》,還有美國國父喬治·華盛頓、墨西哥女畫家芙烈達·卡蘿(Frida Kahlo)、有著血腥瑪莉之稱的瑪麗皇后一世(Mary I of England)、有著賢明女王之稱的伊莉莎白一世(Queen Elizabeth I)等等知名的人物。其他人物真的都覺得還好,只是那個蒙娜麗莎….真的跟想像中的出入頗大啊!

↑賢明女王之稱的伊莉莎白一世(Queen Elizabeth I)。

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

 

↑美國國父喬治·華盛頓。

 

↑瑪麗皇后一世(Mary I of England)。

 

↑墨西哥女畫家芙烈達·卡蘿(Frida Kahlo)、

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

展望智慧汽車未來,高通端出 5nm 新世代 Snapdragon 汽車駕駛座平台_台中搬家公司

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

面對次世代智慧汽車的連網、娛樂,乃至於更進階的自動駕駛、駕駛監控 / 乘客偵測等偏重影像與感測器連結方面的算力需求,並且也同時對應有著成本、複雜性等考量的車廠的客製彈性。高通透過最新第四代 Snapdragon 汽車駕駛座系列平台(Snapdragon Automotive Cockpit Platforms),準備重新定義連網汽車,全力打造未來智慧汽車數位座艙的骨幹架構。繼續閱讀展望智慧汽車未來,高通端出 5nm 新世代 Snapdragon 汽車駕駛座平台報導內文。

▲圖片來源:高通

重新定義連網汽車,高通端出 5nm 新世代 Snapdragon 汽車駕駛座平台

隨著科技的進步,汽車產業的變化不僅止於自動輔助駕駛科技的發展,更多是在於被定義為「第二起居室」的汽車數位座艙的需求有著劇烈的轉變 — 最顯而易見的是滿滿的螢幕,將更為流行的數位後視鏡還是螢幕!

各位也別覺得意外,畢竟大多數人真正的客廳娛樂與物聯系統,乃至於手上拿著的智慧裝置在包括導航等各項功能進化的速度這麼快。車輛產業如果不跟著不斷進化,是要怎麼成為符合車主需求的第二空間呢?

在這兩天高通所舉辦的線上技術展演「重新定義連網汽車」發表會裡,他們透過介紹最新採用 5nm 製程的新世代高通 Snapdragon 車用平台,讓我們有機會一窺那個全自動駕駛,可能已經不是什麼新鮮事的未來樣貌。

真的別覺得自動駕駛很遙遠。就這次同時也公佈的 Snapdragon Ride 駕駛平台的資訊,從僅需 10TOPS 算力的 L1 / L2,到運用了 Qualcomm ADAS 60 / Autonomous 300 駕馭加速器晶片,算力最高來到 700+ TOPS 的 L4/L5 全自動駕駛範疇,其實都有在他們 ADAS 應用處理晶片的規劃中。

為了對應自動駕駛的需求,Snapdragon Ride 平台既然能以單 SoC 對應 ASIL-D 安全等級與 NCAP 等的自動駕駛規範,並確認高通車用平台的 L2 駕駛輔助系統將會在 2024 年量產的計畫。藉由深度整合車輛的各式感測器,Snapdragon Ride 也同樣支援已經在中國推動的 C-V2X 技術。不僅能偵測路側設施,高通更想藉由與其他車輛乃至於行人身上的設備來融入道路的主動感測,達到零事故的理想目標。

談到次世代的智慧汽車,高通認為在綜合的需求驅動下,汽車數位座艙需要演進至區域電子/電機(E / E)運算架構。這也是第四代高通 Snapdragon 汽車駕駛座系列平台希望提供車廠的解決方案。

透過 5nm 製程,採第六代高通 Kryo 與 Hexagon 的處理器,搭配多核高通 AI 引擎、第六代高通 Adreno GPU 及高通 Spectra 影像訊號處理器,將能提供真正可以撐起平台的高運算效能。還對應能源有限且環境相對嚴苛的車輛散熱需求,提供低功耗與高散熱設計,還能輕鬆支援 OTA 更新的特性。

個人認為這次第四代平台的厲害之處,是在於可以對應不同需求的高擴展性。簡而言之,就是對應不同的車款等級(當然,跟車價絕對是正相關 XD),第四代高通 Snapdragon 汽車駕駛座平台都有相應的解決方案。

其實就上面列出的規格,就知道針對車輛感測器與娛樂系統所需要的算力,高通都有對應的級別,除了入門平台的 Performance(效能級),更進階的 Premiere(旗艦級)與支援更強大運算能力的 Paramount(至尊級),後兩者更還有 Plus 版本可對應車款設計需求來提供車廠搭配選用。至於在連線方面更高效的 5G、Wi-Fi 6 以及 Bluetooth 5.2 等更先進連線規格的支援,顯然也是難不倒高通(行動裝置都做這麼久了,感覺應該是一塊蛋糕那樣的簡單吧?)。

相對於算力與 AI 方面的效能提升,更好的體驗、安全性、舒適度與可靠性雖然也很重要。但小編認為這次第四代高通 Snapdragon 汽車駕駛座平台主要瞄準的目標,是更高度整合一切資源與支援的連網汽車生態系。

雖然打造卓越車載系統所需要投入的成本與努力絕對不會低。但藉由高通為汽車產業所打造的優異平台與架構框架,相信對於車廠而言,將會是一個可以降低開發複雜性與維護成本的優異解決方案。這在追求高效率的現代,降低複雜度更意味著縮短商用化耗時以及不浪費成本。這難道不是車廠最夢寐以求的目標嗎?

根據高通的資訊,全新的數位座艙系列平台將於明年量產;開發套件則是今年年第二季便會提供。

本篇圖片 / 引用來源:Qualcomm

延伸閱讀:

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔

M1 MacBook Air 開箱體驗:最驚喜的不變

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

萬字總結之反射(框架之魂)_網頁設計公司

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

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

前言

準備過年看下Spring源碼,用來唬人,哈哈哈哈。正經點,是為了在遇到問題的時候,能知其然而知其所以然。但是在開始前,先惡補下基礎知識。今天看框架之魂——反射。

反射的概述(基礎部分開始)

反射是在編譯狀態,對某個類一無所知 ,但在運行狀態中,對於任意一個類,都能知道這個類的所有屬性和方法。

這個說太乾澀了,沒有靈魂,就像下面兩張圖。

所以咱來舉個例子,拒絕沒有靈魂。O(∩_∩)O哈哈~

為什麼要反射?

如果我們沒有Orange類,那該類在編譯的時候就會報錯找不到該類。這是我們平常使用的“正射”。這個名字是為了和反射相對應,不是官方的術語。

但是這存在着一個明顯的缺點,就是在main方法里調用的是Apple類,並沒有調用Orange類,所以應該是可以正常調用的,當我想要調用Orange類的時候,再報錯即可。但是,事與願違,事情不是照着我們的想法而發展的。

我們需要一種在編譯時不檢查類的調用情況,只有在運行時,才根據相應的要求調用相應的類,這就是“反射”。

反射的用途

反射最重要的用途就是開發各種通用框架。很多框架(比如 Spring)都是配置化的(比如通過 XML 文件配置 Bean),為了保證框架的通用性,它們可能需要根據配置文件加載不同的對象或類,調用不同的方法,這個時候就必須用到反射,運行時動態加載需要加載的對象。

舉一個例子,在運用 Struts 2 框架的開發中我們一般會在 struts.xml 里去配置 Action,比如:

<action name="login"       
        class="org.ScZyhSoft.test.action.SimpleLoginAction"   
        method="execute">      
      <result>/shop/shop-index.jsp</result>     
      <result name="error">login.jsp</result>
</action> 

配置文件與 
Action 建立了一種映射關係,當 View 層發出請求時,請求會被 
StrutsPrepareAndExecuteFilter 攔截,然後 
StrutsPrepareAndExecuteFilter 會去動態地創建 Action 實例。比如我們請求 
login.action,那麼 
StrutsPrepareAndExecuteFilter就會去解析struts.xml文件,檢索action中name為login的Action,並根據class屬性創建SimpleLoginAction實例,並用invoke方法來調用execute方法,這個過程離不開反射。

獲取Class文件對象的三種方式

萬事萬物都是對象。

Apple apple=new Apple();中的apple為Apple的一個實例。那Apple對象是哪個的實例呢?

其實是Class類的實例。

我們可以看他的註釋,私有的構造方法,只有JVM才能創建對象。

如果我們能找到某個對象的Class類,即可以創建其實例。

  • 靜態屬性class
  • Object類的getClass方法,如果知道實例,直接調用其getClass方法。
  • Class類的靜態方法forName(),參數為類的完整路徑(推薦使用)

這裏需要注意,通過類的全路徑名獲取Class對象會拋出一個異常,要用try….catch…捕獲異常。如果根據類路徑找不到這個類那麼就會拋出這個異常,Class類中forName方法源碼如下:

注:雖然寫了三種方式,但平常使用最多,最推薦的是第三種方式,因為第一種方式需要知道類,第二種方式需要知道實例,如果知道了這些,可以直接調用其方法和參數,沒必要再用Class來實現功能。舉個例子,你從北京去上海,第一種方式直達就行,第二種方式和第三種方式則是先從北京到雲南,再從雲南到上海,顯得太冗餘。

反射的使用

我們以Apple類為例,利用發射來獲取其參數和方法。其有三個參數,默認default參數color,公有public參數size,私有private參數price。三個構造方法,分別是默認default構造,公有public帶有三個參數的有參構造,私有帶有兩個參數的有參構造。六個setter/getter方法公有方法,分別是color的默認default隔離級別的setter/getter方法,size的public隔離級別的setter/getter方法,price的private隔離級別的setter/getter方法。toString和三個參數的setter/getter方法。最後還有一個public隔離級別的toString方法。這樣詳細展開的描述,看起來很複雜,其實很簡單的,具體代碼如下:

package com.eastrobot.reflect;

public class Apple extends Fruit{
    String color;//默認default
    public int size;
    private int price;

    Apple() {//默認default
        System.out.println("Apple的無參構造");
    }

    public Apple(String color, int size, int price) {
        this.color = color;
        this.size = size;
        this.price = price;
        System.out.println("Apple的有參構造——三個參數");
    }

    private Apple(String color, int size) {
        this.color = color;
        this.size = size;
        this.price = 10;
        System.out.println("Apple的有參構造——兩個參數");
    }

    @Override
    public String toString() {
        return "color:" + color + ",size:" + size + ",price:" + price;
    }

    //默認default
    String getColor() {
        return color;
    }

    public int getSize() {
        return size;
    }

    private int getPrice() {
        return price;
    }

    //默認default
    void setColor(String color) {
        this.color = color;
    }

    public void setSize(int size) {
        this.size = size;
    }

    private void setPrice(int price) {
        this.price = price;
    }
}

 

繼承的父類Fruit,包括一個public類型的參數taste,和其public類型的setter/getter方法。

public class Fruit {   
 public String taste; 
 public String getTaste() {  
      return taste;    
 }   
 public void setTaste(String taste) {   
     this.taste = taste;  
  }
}

 

1.通過反射獲取所有參數 getDeclaredFields

System.out.println("getDeclaredFields**********");
Field[] fields=appleClass.getDeclaredFields();
for(Field field:fields){   
 System.out.println(field.toString());
}

 

運行結果如下:

注:不管何種隔離級別,getDeclaredFields都會獲取到所有參數。

2.通過反射獲取指定參數getDeclaredField

//指定參數
System.out.println("getDeclaredField**********");
Field colorField=appleClass.getDeclaredField("color");
System.out.println("color:"+colorField.toString());

Field sizeField=appleClass.getDeclaredField("size");
System.out.println("size:"+sizeField.toString());

Field priceField=appleClass.getDeclaredField("price");
System.out.println("price:"+priceField.toString());

 

運行結果如下:

注:不管何種隔離級別,getDeclaredField可以通過輸入值獲取指定參數。

3.通過反射獲取所有pubic類型的參數 getFields

System.out.println("getFields**********");
Field[] fields=appleClass.getFields();
for(Field field:fields){    
    System.out.println(field.toString());
}

 

運行結果如下:

注:只能通過反射獲取public類型的屬性,也包括繼承自父類的屬性。

4.通過反射獲取指定public類型的參數 getField

Field colorField=appleClass.getField("color");
System.out.println("color:"+colorField.toString());

 

運行結果如下:

——————-手動分割線——————-

Field sizeField=appleClass.getField("size");
System.out.println("size:"+sizeField.toString());

 

運行結果如下:

——————-手動分割線——————-

Field priceField=appleClass.getField("price");
System.out.println("price:"+priceField.toString());

 

運行結果如下:

注:只有public類型才能通過getField方法獲取到,其他類型均獲取不到。

看到這裏,有些小夥伴要問了,這是為啥,理由呢?咱不能死記硬背,這樣過两天就忘了,記得不牢固,咱來瞅瞅底層幹了啥。

插曲:為什麼getFields和getField只能獲取public類型的字段?

我們以getField為例,觀察getDeclaredField和getField的區別,可以看到兩者都調用了privateGetDeclaredFields方法,但是區別是getDeclaredField方法中的參數publicOnly是false,getField方法中的參數publicOnly為true。

getDeclaredField方法:

getField方法:

那privateGetDeclaredFields裏面幹了啥,我們看下。

我們可以看到如果為true,就取declaredPublicFields字段,即public字段,如果為false,就取DeclaredFields。

5.通過反射獲取所有方法 getDeclaredMethods

//所有方法
System.out.println("getDeclaredMethods**********");
Method[] methods=appleClass.getDeclaredMethods();
for(Method method:methods){    
    System.out.println(method.toString());
}

 

運行結果如下:

6.通過反射獲取指定方法 getDeclaredMethod

//指定方法
System.out.println("getDeclaredMethod**********");

//default
Method getColorMethod=appleClass.getDeclaredMethod("getColor");
System.out.println("getColorMethod:"+getColorMethod.toString());

//public
Method getSizeMethod=appleClass.getDeclaredMethod("getSize");
System.out.println("getSizeMethod:"+getSizeMethod.toString());

//private
Method getPriceMethod=appleClass.getDeclaredMethod("getPrice");
System.out.println("getPriceMethod:"+getPriceMethod.toString());

//父類的public
Method getTasteMethod=appleClass.getDeclaredMethod("getTaste");
System.out.println("getTasteMethod:"+getTasteMethod.toString());

 

運行結果如下:

注:getDeclaredMethod只能獲取自己定義的方法,不能獲取從父類的方法。

7.通過反射獲取所有public類型的方法 getMethods

//所有方法
System.out.println("getMethods**********");
Method[] methods=appleClass.getMethods();
for(Method method:methods){
    System.out.println(method.toString());
}

 

運行結果如下:

注:getMethods可以通過反射獲取所有的public方法,包括父類的public方法。

8.通過反射獲取指定public類型的方法 getMethod

//指定方法
System.out.println("getMethod**********");
Method method=appleClass.getMethod("toString");
System.out.println(method.toString());

 

運行結果如下:

9.通過反射獲取所有構造方法 getDeclaredConstuctors

//構造方法
System.out.println("getDeclaredConstructors**********");
Constructor[] constructors=appleClass.getDeclaredConstructors();
for(Constructor constructor:constructors){   
 System.out.println(constructor.toString());
}

 

運行結果如下:

10.通過反射獲取某個帶參數的構造方法 getDeclaredConstructor

//指定構造方法
System.out.println("getDeclaredConstructor**********");
Class[] cArg = new Class[3];
cArg[0] = String.class;
cArg[1] = int.class;
cArg[2] = int.class;
Constructor constructor=appleClass.getDeclaredConstructor(cArg);
System.out.println(constructor.toString());

 

運行結果如下:

11.通過反射獲取所有public類型的構造方法getConstructors

System.out.println("getConstructors**********");
Constructor[] constructors=appleClass.getConstructors();
for(Constructor constructor:constructors){
    System.out.println(constructor.toString());
}

 

運行結果:

12.通過反射獲取某個public類型的構造方法getConstructor

//構造方法
System.out.println("getConstructor**********");
Constructor constructor1 = appleClass.getConstructor(String.class,int.class,int.class);
System.out.println("public類型的有參構造:" + constructor1.toString());

Constructor constructor2 = appleClass.getConstructor(String.class, int.class);
System.out.println("private類型的有參構造:" + constructor2.toString());

 

運行結果:

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

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

13.通過無參構造來獲取該類對象 newInstance()

//調用無參構造創建對象
Class appleClass = Class.forName("com.eastrobot.reflect.Apple");
Apple apple=(Apple)appleClass.newInstance();

 

運行結果如下:

14.通過有參構造來獲取該類對象 newInstance(XXXX)

Constructor constructor=appleClass.getConstructor(String.class,int.class,int.class);
Apple apple=(Apple)constructor.newInstance("紅色",10,5);

 

運行結果如下:

15.獲取類名包含包路徑 getName()

String name= appleClass.getName();
System.out.println("name:"+name);

 

運行結果如下:

16.獲取類名不包含包路徑 getSimpleName()

String simpleName =appleClass.getSimpleName();
System.out.println("simpleName:"+simpleName);

 

運行結果如下:

17.通過反射調用方法 invoke

//調用無參構造創建對象
Class appleClass = Class.forName("com.eastrobot.reflect.Apple");

//調用有參構造
Constructor constructor = appleClass.getDeclaredConstructor(String.class, int.class, int.class);
Apple apple = (Apple) constructor.newInstance("紅色", 10, 20);

//獲取toString方法並調用
Method method = appleClass.getDeclaredMethod("toString");
String str=(String)method.invoke(apple);
System.out.println(str);

 

注:invoke+實例可以調用相關public方法。

18.判斷方法是否能調用isAccessible

//調用無參構造創建對象
Class appleClass = Class.forName("com.eastrobot.reflect.Apple");

//調用有參構造
Constructor constructor = appleClass.getDeclaredConstructor(String.class, int.class, int.class);
Apple apple = (Apple) constructor.newInstance("紅色", 10, 20);

//獲取public的getSize方法並調用
Method method = appleClass.getDeclaredMethod("getSize");
System.out.println("getSize方法的isAccessible:" + method.isAccessible());
int size = (Integer) method.invoke(apple);
System.out.println("size:" + size);

//獲取private的getPrice方法並調用
method = appleClass.getDeclaredMethod("getPrice");
System.out.println("getPrice的isAccessible:" + method.isAccessible());
int price = (Integer) method.invoke(apple);
System.out.println("price:" + price);

 

運行結果:

注:這樣一看,public和private類型的isAccessible都為false,但是public類型的值可以獲取到,但是private類型的值並不能獲取到。其實isAccessible()值為 true或false,是指啟用和禁用訪問安全檢查的開關,如果為true,則取消安全檢查,為false,則執行安全檢查。如上,兩者都為false,說明兩者的進行了安全檢查,getSize為public類型,則可以獲取值,而getPrice為private,則不能獲取值。

19.設置安全檢查開關setAccessible

//調用無參構造創建對象
Class appleClass = Class.forName("com.eastrobot.reflect.Apple");

//調用有參構造
Constructor constructor = appleClass.getDeclaredConstructor(String.class, int.class, int.class);
Apple apple = (Apple) constructor.newInstance("紅色", 10, 20);

//獲取price
Method otherMethod = appleClass.getDeclaredMethod("getPrice");
System.out.println("getPrice方法的isAccessible:" + otherMethod.isAccessible());
otherMethod.setAccessible(true);
int price = (Integer) otherMethod.invoke(apple);
System.out.println("之前的price:" + price);

//重新設置price
Method method = appleClass.getDeclaredMethod("setPrice", int.class);
System.out.println("isAccessible:" + method.isAccessible());
method.setAccessible(true);
method.invoke(apple, 100);

//再次獲取price
otherMethod = appleClass.getDeclaredMethod("getPrice");
otherMethod.setAccessible(true);
price = (Integer) otherMethod.invoke(apple);
System.out.println("之後的price:" + price);

 

運行結果:

注:setAccessible(true)表示取消安全檢查,setAccessible(false)表示啟用安全檢查。

常見面試題解答(進階部分開始)

被反射的類是否一定需要無參構造方法?

不一樣。因為有參構造方法也可以反射,具體代碼如下:

Constructor constructor=appleClass.getConstructor(String.class,int.class,int.class);
Apple apple=(Apple)constructor.newInstance("紅色",10,5);

 

反射的使用有什麼優勢和劣勢?

優勢:

在編譯時根本無法知道該對象或類可能屬於哪些類,程序只依靠運行時信息來發現該對象和類的真實信息。反射提高了Java程序的靈活性和擴展性,降低耦合性,提高自適應能力。它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。

劣勢:

使用反射基本上是一種解釋操作,用於字段和方法接入時要遠慢於直接代碼

使用反射會模糊程序內部邏輯,程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術,因而會帶來維護問題。(這也就是看源碼為什麼這麼難?哎。。。。)

為什麼說反射可以降低耦合?

因為反射不是硬編碼,在運行時可以靈活發現該類的詳細信息,降低了代碼之間的耦合性。

反射比較損耗性能,為什麼這樣說?(重點)

怎麼去判斷一個函數的性能?因為函數的執行太快太快了,你需要一個放慢鏡,這樣才能捕捉到他的速度。怎麼做?把一個函數執行一百萬遍或者一千萬遍,你才能真正了解一個函數的性能。也就是,你如果想判斷性能,你就不能還停留在秒級,毫秒級的概念。

如下是將直接獲取實例,直接獲取方法,反射獲取實例,反射獲取方法分別執行1百萬次所花費差。

try {    
    //直接獲取實例
    long startTime1 = System.currentTimeMillis();   
    for (int i = 0; i < 1000000; i++) { 
       new Apple();   
    }  
    long endTime1 = System.currentTimeMillis();  
    System.out.println("直接獲取實例時間:" + (endTime1 - startTime1));   
 
    //直接獲取方法  
    long startTime2= System.currentTimeMillis();   
    for (int i = 0; i < 1000000; i++) {  
      new Apple().toString();   
    }  
    long endTime2 = System.currentTimeMillis();  
    System.out.println("直接獲取方法時間:" + (endTime2- startTime2)); 
   
   //反射獲取實例  
   Class appleClass=Class.forName("com.eastrobot.reflect.Apple");   
   long startTime3 = System.currentTimeMillis();   
   for (int i = 0; i < 1000000; i++) {
       appleClass.getDeclaredConstructor().newInstance();  
    }   
   long endTime3 = System.currentTimeMillis(); 
   System.out.println("反射獲取實例:" + (endTime3 - startTime3));   
 
   //反射獲取方法  
   Apple apple= (Apple)appleClass.getDeclaredConstructor().newInstance();   
   long startTime4 = System.currentTimeMillis();   
   for (int i = 0; i < 1000000; i++) {    
     Method method=appleClass.getMethod("toString");    
     method.invoke(apple);   
   }    
   long endTime4 = System.currentTimeMillis();  
   System.out.println("反射獲取方法:" + (endTime4 - startTime4));

 

運行結果截圖:

我們可以看到反射的確會導致性能問題,但反射導致的性能問題是否嚴重跟使用的次數有關係,如果控制在100次以內,基本上沒什麼差別,如果調用次數超過了100次,性能差異會很明顯。

打個比方,如果快遞員就在你住的小區,那麼你報一個地址:xx棟xx號,那麼快遞員就可以馬上知道你在哪裡,直接就去到你家門口;但是,如果快遞員是第一次來你們這裏,他是不是首先得查查百度地圖,看看怎麼開車過去,然後到了小區是不是得先問問物管xx棟怎麼找,然後,有可能轉在樓下轉了兩個圈才到了你的門前。

我們看上面這個場景,如果快遞員不熟悉你的小區,是不是會慢點,他的時間主要花費在了查找百度地圖,詢問物業管理。OK,反射也是一樣,因為我事先什麼都不知道,所以我得花時間查詢一些其他資料,然後我才能找到你。

綜上,大部分我們使用反射是不考慮性能的,平常使用的次數較少,如果真的遇到性能問題,如反射的效率影響到程序邏輯,可以採用緩存或Java字節碼增強技術,參照庫有asm,也有第三方工具庫reflectAsm(https://github.com/EsotericSoftware/reflectasm)。

反射中的setAccessible()方法是否破壞了類的訪問規則

setAccessible(true)取消了Java的權限控制檢查(注意不是改變方法或字段的訪問權限),對於setAccessible()方法是否會破壞類的訪問規則,產生安全隱患,見下:

反射源碼解析

我們跟進Method的invoke方法,分為兩步,一是語言訪問級別是否為重寫,如果不是重寫則調用Reflection的quickCheckMemberAccess方法,即通過Modifiers 判斷是否具有訪問權限,quickCheckMemberAccess方法主要是簡單地判斷 modifiers 是不是 public,如果不是的話就返回 false。所以 protected、private、default 修飾符都會返回 false,只有 public 都會返回 true。如果為false,則調用checkAccess方法。二是獲取MethodAccessor對象,並調用其invoke方法。

public final class Method extends AccessibleObject implements GenericDeclaration, Member {   
     private volatile MethodAccessor methodAccessor; 
    //每個Java方法只有一個對應Method對象作為root,這個root不會暴露給用戶,
    //而是每次通過反射獲取Method對象時新創建的Method對象將root包裝起來。
     private Method   root;

    @CallerSensitive 
    public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;
        //在第一次調用一個實際Java方法應該的Method對象的invoke方法之前
        //實現調用邏輯的MethodAccessor對象還沒有創建
        //等到第一次調用時才創建MethodAccessor,並通過該MethodAccessor.invoke真正完成反射調用
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        //invoke並不是自己實現的反射調用邏輯,而是委託給sun.reflect.MethodAccessor來處理
        return ma.invoke(obj, args);
    } 

    ...

     private MethodAccessor acquireMethodAccessor() {
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
            methodAccessor = tmp;
        } else {
            //調用ReflectionFactory的newMethodAccessor方法,見下
            tmp = reflectionFactory.newMethodAccessor(this);
            //更新root,以便下次直接使用
            setMethodAccessor(tmp);
        }
        return tmp;
    }

    ...

     void setMethodAccessor(MethodAccessor accessor) {
        methodAccessor = accessor;
        // Propagate up
        if (root != null) {
            root.setMethodAccessor(accessor);
        }
    }

 

Reflection類:

public static boolean quickCheckMemberAccess(Class<?> memberClass,
                                                 int modifiers)
{
    return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers);
} 

 

ReflectionFactory類:

 

private static boolean noInflation = false;
//選擇java版還是C語言版的閾值
private static int inflationThreshold = 15;

public MethodAccessor newMethodAccessor(Method var1) {
        checkInitted();
        if (noInflation) {
            //java版
            return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
        } else {
            //c語言版
            NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
            DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
            var2.setParent(var3);
            return var3;
        }
    }

如上述代碼所示,實際的MethodAccessor實現有兩個版本,一個是Java實現的,另一個是native code實現的。Java實現的版本在初始化時需要較多時間,但長久來說性能較好;native版本正好相反,啟動時相對較快,但運行時間長了之後速度就比不過Java版了。這是HotSpot的優化方式帶來的性能特性,同時也是許多虛擬機的共同點:跨越native邊界會對優化有阻礙作用,它就像個黑箱一樣讓虛擬機難以分析也將其內聯,於是運行時間長了之後反而是託管版本的代碼更快些。

為了權衡兩個版本的性能,Sun的JDK使用了“inflation”的技巧:讓Java方法在被反射調用時,開頭若干次使用native版,等反射調用次數超過閾值時則生成一個專用的MethodAccessor實現類,生成其中的invoke()方法的字節碼,以後對該Java方法的反射調用就會使用Java版。
Sun的JDK是從1.4系開始採用這種優化的,主要作者是Ken Russell

MethodAccessor的C語言實現(默認)

C語言版的MethodAccessor主要涉及這NativeMethodAccessorImpl和DelegatingMethodAccessorImpl兩個類,而DelegatingMethodAccessorImpl是間接層,不是太重要,就不貼代碼啦。以下是NativeMethodAccessorImpl的代碼,核心是invoke方法:

 

class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private final Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;

    NativeMethodAccessorImpl(Method var1) {
        this.method = var1;
    }

    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold()) {
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }

    void setParent(DelegatingMethodAccessorImpl var1) {
        this.parent = var1;
    }

    private static native Object invoke0(Method var0, Object var1, Object[] var2);
}

 

 

 

 


每次NativeMethodAccessorImpl.invoke()方法被調用時,都會增加一個調用次數計數器,看超過閾值沒有;一旦超過,則調用MethodAccessorGenerator.generateMethod()來生成Java版的MethodAccessor的實現類,並且改變DelegatingMethodAccessorImpl所引用的MethodAccessor為Java版。後續經由DelegatingMethodAccessorImpl.invoke()調用到的就是Java版的實現了。

MethodAccessor的Java實現

 return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());

 


Java的MethodAccessor主要涉及的是MethodAccessorGenerator類,具體代碼超長,只截取了部分代碼,主要有三個方法,直接就是上述的generateMethod方法,代碼如下:

 

public MethodAccessor generateMethod(Class var1, String var2, Class[] var3, Class var4, Class[] var5, int var6) {
        return (MethodAccessor)this.generate(var1, var2, var3, var4, var5, var6, false, false, (Class)null);
    }
 private MagicAccessorImpl generate(final Class var1, String var2, Class[] var3, Class var4, Class[] var5, int var6, boolean var7, boolean var8, Class var9) {
        ByteVector var10 = ByteVectorFactory.create();
        this.asm = new ClassFileAssembler(var10);
        this.declaringClass = var1;
        this.parameterTypes = var3;
        this.returnType = var4;
        this.modifiers = var6;
        this.isConstructor = var7;
        this.forSerialization = var8;
        this.asm.emitMagicAndVersion();
        short var11 = 42;
        boolean var12 = this.usesPrimitiveTypes();
        if (var12) {
            var11 = (short)(var11 + 72);
        }

        if (var8) {
            var11 = (short)(var11 + 2);
        }

        var11 += (short)(2 * this.numNonPrimitiveParameterTypes());
        this.asm.emitShort(add(var11, (short)1));
        final String var13 = generateName(var7, var8);
        this.asm.emitConstantPoolUTF8(var13);
        this.asm.emitConstantPoolClass(this.asm.cpi());
        this.thisClass = this.asm.cpi();
        if (var7) {
            if (var8) {
                this.asm.emitConstantPoolUTF8("sun/reflect/SerializationConstructorAccessorImpl");
            } else {
                this.asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl");
            }
        } else {
            this.asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl");
        }

        this.asm.emitConstantPoolClass(this.asm.cpi());
        this.superClass = this.asm.cpi();
        this.asm.emitConstantPoolUTF8(getClassName(var1, false));
        this.asm.emitConstantPoolClass(this.asm.cpi());
        this.targetClass = this.asm.cpi();
        short var14 = 0;
        if (var8) {
            this.asm.emitConstantPoolUTF8(getClassName(var9, false));
            this.asm.emitConstantPoolClass(this.asm.cpi());
            var14 = this.asm.cpi();
        }

        this.asm.emitConstantPoolUTF8(var2);
        this.asm.emitConstantPoolUTF8(this.buildInternalSignature());
        this.asm.emitConstantPoolNameAndType(sub(this.asm.cpi(), (short)1), this.asm.cpi());
        if (this.isInterface()) {
            this.asm.emitConstantPoolInterfaceMethodref(this.targetClass, this.asm.cpi());
        } else if (var8) {
            this.asm.emitConstantPoolMethodref(var14, this.asm.cpi());
        } else {
            this.asm.emitConstantPoolMethodref(this.targetClass, this.asm.cpi());
        }

        this.targetMethodRef = this.asm.cpi();
        if (var7) {
            this.asm.emitConstantPoolUTF8("newInstance");
        } else {
            this.asm.emitConstantPoolUTF8("invoke");
        }

        this.invokeIdx = this.asm.cpi();
        if (var7) {
            this.asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
        } else {
            this.asm.emitConstantPoolUTF8("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
        }

        this.invokeDescriptorIdx = this.asm.cpi();
        this.nonPrimitiveParametersBaseIdx = add(this.asm.cpi(), (short)2);

        for(int var15 = 0; var15 < var3.length; ++var15) {
            Class var16 = var3[var15];
            if (!isPrimitive(var16)) {
                this.asm.emitConstantPoolUTF8(getClassName(var16, false));
                this.asm.emitConstantPoolClass(this.asm.cpi());
            }
        }

        this.emitCommonConstantPoolEntries();
        if (var12) {
            this.emitBoxingContantPoolEntries();
        }

        if (this.asm.cpi() != var11) {
            throw new InternalError("Adjust this code (cpi = " + this.asm.cpi() + ", numCPEntries = " + var11 + ")");
        } else {
            this.asm.emitShort((short)1);
            this.asm.emitShort(this.thisClass);
            this.asm.emitShort(this.superClass);
            this.asm.emitShort((short)0);
            this.asm.emitShort((short)0);
            this.asm.emitShort((short)2);
            this.emitConstructor();
            this.emitInvoke();
            this.asm.emitShort((short)0);
            var10.trim();
            final byte[] var17 = var10.getData();
            return (MagicAccessorImpl)AccessController.doPrivileged(new PrivilegedAction<MagicAccessorImpl>() {
                public MagicAccessorImpl run() {
                    try {
                        return (MagicAccessorImpl)ClassDefiner.defineClass(var13, var17, 0, var17.length, var1.getClassLoader()).newInstance();
                    } catch (InstantiationException var2) {
                        throw (InternalError)(new InternalError()).initCause(var2);
                    } catch (IllegalAccessException var3) {
                        throw (InternalError)(new InternalError()).initCause(var3);
                    }
                }
            });
        }
    } 
private static synchronized String generateName(boolean var0, boolean var1) {
        int var2;
        if (var0) {
            if (var1) {
                var2 = ++serializationConstructorSymnum;
                return "sun/reflect/GeneratedSerializationConstructorAccessor" + var2;
            } else {
                var2 = ++constructorSymnum;
                return "sun/reflect/GeneratedConstructorAccessor" + var2;
            }
        } else {
            var2 = ++methodSymnum;
            return "sun/reflect/GeneratedMethodAccessor" + var2;
        }
    }

 

 

 

 


去閱讀源碼的話,可以看到MethodAccessorGenerator是如何一點點把Java版的MethodAccessor實現類生產出來的,其實就是一個逐步解析的過程。

此時要注意的是最後的“sun/reflect/GeneratedMethodAccessor”+var2的代碼。

例子

以上空說無用,太乾澀,咱來個例子。

 

public class Foo {

public void foo(String name) {       
     System.out.println("Hello, " + name); 
   }
}

 

public class test {    
    public static void main(String[] args) {  
          try {          
                  Class<?> clz = Class.forName("com.eastrobot.reflect.Foo");      
                  Object o = clz.newInstance();  
                  Method m = clz.getMethod("foo", String.class);    
                  for (int i = 0; i < 17; i++) {        
                        m.invoke(o, Integer.toString(i));      
                  }       
         } catch (Exception e) {
         } 
   }
}

 

除了上述代碼,還需要在idea配置相關的運行參數,添加-XX:+TraceClassLoading參數,其為要求打印加載類的監控信息。

我們先用上述的例子執行下,運行結果如下,前面十五次是正常的,到第16次的時候,出現了很多打印信息,我已將一行標紅,“GeneratedMethodAccessor1”,這其實就是上面說的Java版獲取MethodAccessorGenerator的最後一行,1為自增參數。當第17次的時候,就不會用Java版的方式重新獲取,而是直接復用啦。

 

結語

終於結束了,邊玩邊寫,寫了五天,累死了,答應我,一定要好好看,好嗎?

如有說的不對地方,歡迎指正。

參考資料

Java反射詳細介紹

Java反射中getDeclaredField和getField的區別

java反射的使用場合和作用、及其優缺點

反射是否真的會讓你的程序性能降低?

深入解析Java反射(1) – 基礎

關於反射調用方法的一個log 

反射進階,編寫反射代碼值得注意的諸多細節

 

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

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

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

【Redis面試題】如何使用Redis實現微信步數排行榜?_如何寫文案

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

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

1. 前言

之前寫過一篇博客,講解的是Redis的5種數據結構及其常用命令,當時有讀者評論,說希望了解下這5種數據結構各自的使用場景,不過一直也沒來得及寫。

碰巧,在3月份找工作面試時,有個面試官先問了我Redis有哪幾種數據結構,在我講完后,面試官又問了我以下問題:

如何用Redis實現微信步數排行榜?

相信很多小夥伴都知道,可以使用Redis的有序集合ZSET來實現,本篇博客就基於此面試題,來講解下ZSET的使用場景,以及微信步數排行榜的大致實現思路。

2. ZSET的使用場景

ZSET的經典使用場景是用來實現排行榜,舉幾個常見的例子,比如百度熱榜、微博熱搜榜、以及我們每天都用到的微信步數排行榜:

3個場景的實現思路基本一致,接下來,我們以微信步數排行榜為例,了解下如何使用Redis的ZSET,實現微信步數排行榜。

3. 微信步數排行榜的大致實現思路

注意事項:本文的重點是Redis的ZSET的使用,因此只是分析了微信步數排行榜的大致實現思路,實際實現肯定比文中分析的複雜的多。

首先,我們來分析下微信步數排行榜的需求:

  1. 排行榜是以日期為單位的,歷史日期的排行榜是可以查看的
  2. 排行榜可能並不會显示所有好友的步數,比如我的微信有349位好友,但排行榜從來沒有显示過這麼多,假設最多只显示步數前200的好友
  3. 步數是異步更新的,所以每隔一段時間步數同步后,排行榜都會變化
  4. 排行榜中,好友頭像和微信昵稱可以理解為不變的(變動的幾率小,就像熱搜榜中的標題和Url),但步數和點贊數是可變的

基於以上分析的需求,大致實現思路如下:

  1. 使用Redis的ZSET數據結構

  2. 設置key時,基於微信號和日期,比如我的微信是zwwhnly,今天的日期是2020-06-01,那麼key就可以設計為:StepNumberRanking:zwwhnly:20200601

  3. 設置value時,將好友的昵稱作為成員member,將好友的步數作為分值score,如下所示:

  4. 使用Redis的HASH數據結構,其中key為第2步的key+第3步的成員member,value分別存儲好友頭像、昵稱、步數、點贊數,如下所示:

  5. 獲取微信步數排行榜時,分為以下2步:

    1)先查詢出微信步數排行榜中的好友昵稱,也就是查詢StepNumberRanking:zwwhnly:20200601的值

    2)根據獲取到的好友昵稱,查詢好友步數信息,也就是查詢StepNumberRanking:zwwhnly:20200601:yst的值

4. 使用到的Redis命令

上面分析出了大致的實現思路,接下來我們講解下使用到的Redis命令。

4.1 ZADD

執行如下命令初始化微信步數排行榜,以上面圖片中的9個好友為例,分2次初始化:

ZADD StepNumberRanking:zwwhnly:20200602 25452 yst 23683 zq 23599 ljx 20391 yyq 19628 XxZz

ZADD StepNumberRanking:zwwhnly:20200602 18261 lxx 16636 zcc 16555 clc 16098 fl

執行完的效果如下圖所示:

可以看到,默認是以score正序排列的,也就是步數從少到多排列。

4.2 HMSET

因為展示步數排行榜時,需要展示昵稱、頭像、步數、點贊數,所以可以藉助於Redis的HASH 數據結構來存儲,這時就要用到HMSET命令:

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

執行完的效果如下圖所示:

4.3 ZINCRBY

每隔一段時間,好友的步數是會更新的,此時可以使用ZINCRBY命令來更新好友步數,假設我們只更新步數位於前2位好友的步數,給他們的步數增加10,就可以執行以下命令:

ZINCRBY StepNumberRanking:zwwhnly:20200602 10 yst

ZINCRBY StepNumberRanking:zwwhnly:20200602 10 zq

執行完的效果如下圖所示:

更新完排行榜里的步數后,不要忘記執行HMSET命令更新好友的步數:

4.4 HINCRBY

當我們在步數排行榜里給好友點贊時,可以使用HINCRBY命令,把上圖中的likeNum加1:

HINCRBY StepNumberRanking:zwwhnly:20200602:zq likeNum 1

4.5 ZRANGE

在所有的數據就緒后,剩下的就是查詢了,我們可以使用ZRANGE命令獲取排行榜里的好友信息:

ZRANGE StepNumberRanking:zwwhnly:20200602 0 -1

可以看出,查詢出的好友信息是按步數從少到多排序的,而排行榜應該按步數從多到少排序,這就用到了下面的ZREVRANGE命令。

4.6 ZREVRANGE

ZREVRANGE命令和ZRANGE命令類似,不過是按score倒序的,剛好符合排行榜的場景。

比如執行命令:

ZREVRANGE StepNumberRanking:zwwhnly:20200602 0 -1 WITHSCORES

可以看出,查詢出的好友信息按步數從大到小排序,剛好就是在排行榜要展示的順序。

不過,排行榜一般都不展示所有的數據,這裏我們的數據比較少,如果只獲取步數top5的好友,就可以執行如下命令:

ZREVRANGE StepNumberRanking:zwwhnly:20200602 0 4 WITHSCORES

如果你要獲取top200,就將上面的4修改為199。

4.7 HGETALL

獲取到了排行榜里的好友信息,最後一步就是獲取這些好友的步數、點贊數、頭像、昵稱這些信息,也就是我們之前使用HASH數據結構存儲的信息,此時我們可以使用HGETALL命令,如下所示:

HGETALL StepNumberRanking:zwwhnly:20200602:yst

如果對這些命令不是很熟悉,可以看下我之前發布的一篇博客:Redis系列(二):Redis的5種數據結構及其常用命令。

5. 總結

Redis的ZSET數據結構非常適合用在排行榜的場景,比如百度熱搜、微博熱搜榜、遊戲排行榜、微信步數排行榜,面試官肯定不會問你ZSET都有哪些命令,每個命令的細節等等,但問你如何使用Redis實現微信步數排行榜,就可以了解到你對Redis數據結構的掌握程度。

所以,學習好Redis的5種數據結構的基礎很重要,但更重要的是要知道這些數據結構如何使用,每種數據結構用在什麼場景最為合適,畢竟要學以致用嘛。

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

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

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。