注于Java領域優質技術,歡迎關注
來自:JavaGuide , 作者 SnailClimb
Arrays.asList()在平時開發中還是比較常見的,我們可以使用它將一個數組轉換為一個List集合。
JDK 源碼對于這個方法的說明:
《阿里巴巴Java 開發手冊》對其的描述
Arrays.asList()將數組轉換為集合后,底層其實還是數組,《阿里巴巴Java 開發手冊》對于這個方法有如下描述:
阿里巴巴Java開發手冊-Arrays.asList()方法
傳遞的數組必須是對象數組,而不是基本類型。
Arrays.asList()是泛型方法,傳入的對象必須是對象數組。
當傳入一個原生數據類型數組時,Arrays.asList() 的真正得到的參數就不是數組中的元素,而是數組對象本身!此時List 的唯一元素就是這個數組,這也就解釋了上面的代碼。
我們使用包裝類型數組就可以解決這個問題。
Integer[] myArray={ 1, 2, 3 };
使用集合的修改方法:add()、remove()、clear()會拋出異常。
Arrays.asList() 方法返回的并不是 java.util.ArrayList ,而是 java.util.Arrays 的一個內部類,這個內部類并沒有實現集合的修改方法或者說并沒有重寫這些方法。
List myList=Arrays.asList(1, 2, 3);
System.out.println(myList.getClass());//class java.util.Arrays$ArrayList
下圖是java.util.Arrays$ArrayList的簡易源碼,我們可以看到這個類重寫的方法有哪些。
我們再看一下java.util.AbstractList的remove()方法,這樣我們就明白為啥會拋出UnsupportedOperationException。
public E remove(int index) {
throw new UnsupportedOperationException();
}
如何正確的將數組轉換為ArrayList?
stackoverflow:https://dwz.cn/vcBkTiTW
1. 自己動手實現(教育目的)
2. 最簡便的方法(推薦)
List list=new ArrayList<>(Arrays.asList("a", "b", "c"))
3. 使用 Java8 的Stream(推薦)
4. 使用 Guava(推薦)
對于不可變集合,你可以使用ImmutableList類及其of()與copyOf()工廠方法:(參數不能為空)
對于可變集合,你可以使用Lists類及其newArrayList()工廠方法:
5. 使用 Apache Commons Collections
List<String> list=new ArrayList<String>();
CollectionUtils.addAll(list, str);
現在人工智能非?;鸨芏嗯笥讯枷雽W,但是一般的教程都是為博碩生準備的,太難看懂了。最近發現了一個非常適合小白入門的教程,不僅通俗易懂而且還很風趣幽默。所以忍不住分享一下給大家。點這里可以跳轉到教程。
https://www.captainbed.net/suga
文由掘金@hpstream_授權發布
https://juejin.cn/post/7034796986889043999
談到WebComponent 很多人很容易想到Vue,React中的組件。但其實H5原生也已經支持了組件的編寫。
關于Web Components,MDN是如此定義其概念和使用的:
Web Components 是一套不同的技術,允許您創建可重用的定制元素(它們的功能封裝在您的代碼之外)并且在您的web應用中使用它們。
作為開發者,我們都知道盡可能多的重用代碼是一個好主意。這對于自定義標記結構來說通常不是那么容易 — 想想復雜的HTML(以及相關的樣式和腳本),有時您不得不寫代碼來呈現自定義UI控件,并且如果您不小心的話,多次使用它們會使您的頁面變得一團糟。
Web Components旨在解決這些問題 — 它由三項主要技術組成,它們可以一起使用來創建封裝功能的定制元素,可以在你喜歡的任何地方重用,不必擔心代碼沖突。
?
Custom elements(自定義元素):一組JavaScript API,允許您定義custom elements及其行為,然后可以在您的用戶界面中按照需要使用它們。
?
?
Shadow DOM(影子DOM):一組JavaScript API,用于將封裝的“影子”DOM樹附加到元素(與主文檔DOM分開呈現)并控制其關聯的功能。通過這種方式,您可以保持元素的功能私有,這樣它們就可以被腳本化和樣式化,而不用擔心與文檔的其他部分發生沖突。
?
?
HTML templates(HTML模板):template 和 slot 元素使您可以編寫不在呈現頁面中顯示的標記模板。然后它們可以作為自定義元素結構的基礎被多次重用。
?
上面的概念難以理解,我們通過一個例子看下如何編寫一個組件
「1、什么是 HTML templates(HTML模板)?」
<template id="btn">
<button class="hp-button">
<slot></slot>
</button>
</template>
「2、Custom elements(自定義元素)」
class HpButton extends HTMLElement {
constructor() {
super();
//...
}
}
// 定義了一個自定義標簽 組件
window.customElements.define('hp-button', HpButton)
「3、Shadow DOM(影子DOM)」
let shadow=this.attachShadow({
mode: 'open'
});
let btnTmpl=document.getElementById('btn');
let cloneTemplate=btnTmpl.content.cloneNode(true)
const style=document.createElement('style');
let type=this.getAttribute('type') || 'default';
const btnList={
'primary': {
background: '#ff0000',
color: '#fff'
},
'default': {
background: '#909399',
color: '#fff'
}
}
style.textContent=`
.hp-button{
outline:none;
border:none;
border-radius:4px;
padding:5px 20px;
display:inline-flex;
background:${btnList[type].background};
color:${btnList[type].color};
cursor:pointer
}
`
// dom操作具備移動型
shadow.appendChild(style)
shadow.appendChild(cloneTemplate)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
:root {
--background-color: black;
--text-color: yellow
}
</style>
<hp-button type="primary">
<input type="text">
按鈕
</hp-button>
<hp-button>前端晚間課</hp-button>
<!-- 內容是不會被渲染到視圖上,不會影響頁面展示,可以使用模板 -->
<template id="btn">
<button class="hp-button">
<slot></slot>
</button>
</template>
<script>
class HpButton extends HTMLElement {
constructor() {
super();
let shadow=this.attachShadow({
mode: 'open'
});
let btnTmpl=document.getElementById('btn');
let cloneTemplate=btnTmpl.content.cloneNode(true)
const style=document.createElement('style');
let type=this.getAttribute('type') || 'default';
const btnList={
'primary': {
background: '#ff0000',
color: '#fff'
},
'default': {
background: '#909399',
color: '#fff'
}
}
style.textContent=`
.hp-button{
outline:none;
border:none;
border-radius:4px;
padding:5px 20px;
display:inline-flex;
background:${btnList[type].background};
color:${btnList[type].color};
cursor:pointer
}
`
// dom操作具備移動型
shadow.appendChild(style)
shadow.appendChild(cloneTemplate)
}
}
// 定義了一個自定義標簽 組件
window.customElements.define('hp-button', HpButton)
</script>
</body>
</html>
原生組件與Vue,React的組件的概念是相似的,但是從寫法上來看有區別。
在custom element的構造函數中,可以指定多個不同的回調函數,它們將會在元素的不同生命時期被調用:
我們來看一下它們的一下用法示例。下面的代碼出自life-cycle-callbacks(https://github.com/mdn/web-components-examples/tree/master/life-cycle-callbacks)示例(查看在線示例:https://mdn.github.io/web-components-examples/life-cycle-callbacks/)。這個簡單示例只是生成特定大小、顏色的方塊。custom element看起來像下面這樣:
生命周期的代碼的具體示例:
class Square extends HTMLElement {
// Specify observed attributes so that
// attributeChangedCallback will work
static get observedAttributes() {
return ['c', 'l'];
}
constructor() {
// Always call super first in constructor
super();
const shadow=this.attachShadow({mode: 'open'});
const div=document.createElement('div');
const style=document.createElement('style');
shadow.appendChild(style);
shadow.appendChild(div);
}
connectedCallback() {
console.log('Custom square element added to page.');
updateStyle(this);
}
disconnectedCallback() {
console.log('Custom square element removed from page.');
}
adoptedCallback() {
console.log('Custom square element moved to new page.');
}
attributeChangedCallback(name, oldValue, newValue) {
console.log('Custom square element attributes changed.');
updateStyle(this);
}
}
customElements.define('custom-square', Square);
document.querySelector('???').dispatchEvent(new CustomEvent('changeName', {
detail: {
name: 1111,
}
}))
<!-- 沒有實際意義, 不會渲染到頁面上 -->
<template id="collapse_tmpl">
<div class="zf-collapse">
<slot></slot>
</div>
</template>
<template id="collapse_item_tmpl">
<div class="zf-collapse-item">
<div class="title"></div>
<div class="content">
<slot></slot>
</div>
</div>
</template>
class Collapse extends HTMLElement {
constructor() {
super();
const shadow=this.attachShadow({
mode: 'open'
});
const tmpl=document.getElementById('collapse_tmpl');
let cloneTemplate=tmpl.content.cloneNode(true);
let style=document.createElement('style');
// :host 代表的是影子的根元素
style.textContent=`
:host{
display:flex;
border:3px solid #ebebeb;
border-radius:5px;
width:100%;
}
.zf-collapse{
width:100%;
}
`
shadow.appendChild(style);
shadow.appendChild(cloneTemplate);
let slot=shadow.querySelector('slot'); // 監控slot變化
slot.addEventListener('slotchange', (e)=> {
this.slotList=e.target.assignedElements();
this.render();
})
}
static get observedAttributes() { // 監控屬性的變化
return ['active']
}
// update
attributeChangedCallback(key, oldVal, newVal) {
if (key=='active') {
this.activeList=JSON.parse(newVal);
this.render();
}
}
render() {
if (this.slotList && this.activeList) {
[...this.slotList].forEach(child=> {
child.setAttribute('active', JSON.stringify(this.activeList))
});
}
}
}
export default Collapse
class CollapseItem extends HTMLElement {
constructor() {
super();
let shadow=this.attachShadow({
mode: 'open'
});
let tmpl=document.getElementById('collapse_item_tmpl');
let cloneTemplate=tmpl.content.cloneNode(true);
let style=document.createElement('style');
this.isShow=true; // 標識自己是否需要顯示
style.textContent=`
:host{
width:100%;
}
.title{
background:#f1f1f1;
line-height:35px;
height:35px;
}
.content{
font-size:14px;
}
`
shadow.appendChild(style)
shadow.appendChild(cloneTemplate);
this.titleEle=shadow.querySelector('.title');
this.titleEle.addEventListener('click', ()=> {
// 如果將結果傳遞給父親 組件通信?
document.querySelector('zf-collapse').dispatchEvent(new CustomEvent('changeName', {
detail: {
name: this.getAttribute('name'),
isShow: this.isShow
}
}))
})
}
static get observedAttributes() { // 監控屬性的變化
return ['active', 'title', 'name']
}
// update
attributeChangedCallback(key, oldVal, newVal) {
switch (key) {
case 'active':
this.activeList=JSON.parse(newVal); // 子組件接受父組件的數據
break;
case 'title':
this.titleEle.innerHTML=newVal; // 接受到title屬性 作為dom的title
break;
case 'name':
this.name=newVal
break;
}
let name=this.name;
if (this.activeList && name) {
this.isShow=this.activeList.includes(name);
this.shadowRoot.querySelector('.content').style.display=this.isShow ? 'block' : 'none'
}
}
}
export default CollapseItem
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<zf-collapse>
<zf-collapse-item title="Node" name="1">
<div>nodejs welcome</div>
</zf-collapse-item>
<zf-collapse-item title="react" name="2">
<div>react welcome</div>
</zf-collapse-item>
<zf-collapse-item title="vue" name="3">
<div>vue welcome</div>
</zf-collapse-item>
</zf-collapse>
<!-- 沒有實際意義, 不會渲染到頁面上 -->
<template id="collapse_tmpl">
<div class="zf-collapse">
<slot></slot>
</div>
</template>
<template id="collapse_item_tmpl">
<div class="zf-collapse-item">
<div class="title"></div>
<div class="content">
<slot></slot>
</div>
</div>
</template>
<!-- vite 實現原理 就依賴于 type="module" -->
<script src="./index1.js" type="module"></script>
</body>
</html>
案例Demo(https://github.com/mdn/web-components-examples)
之前的文章鴻蒙應用開發之運行HelloWorld 里我運行了一個穿戴設備的應用,利用JS UI實現了一個最簡單的HelloWorld。
今天我打算在智慧屏設備上利用豆瓣音樂的接口數據實現一個簡單的List界面。
說起來這是一個很簡單的功能實現,不過其中也有不少的坑。
首先要說明的是,鴻蒙應用開發里有Java UI框架和JS UI框架,如果要談界面實現的簡單方便,當然是選用JS UI框架了。
大概的瀏覽了一下JS API的文檔,
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-overview-0000001056361791
我發現鴻蒙應用開發里面的JS限制還是比較多的,和原生的JS差別也很大,不過畢竟是在別人的地盤下開發,還是要入鄉隨俗。
鴻蒙應用的JS UI框架已經有了很多的組件,滿足一般的開發是沒問題的,也提供了自定義組件。
當然也提供了底層接口,可以獲取硬件信息,地理位置等等。
在今天的開發里,我最關心的就是List組件和數據獲取的方式。
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-container-list-0000000000611496
按照文檔里提供的范例,我把index.html改成了如下代碼
<!-- index.hml -->
<div class="container">
<list>
<list-item for="{{data.items}}">
<text class="item">{{$item.name}}</text>
</list-item>
</list>
</div>
在index.js里我把data部分改成了如下:
data: {
data:{
items:[
{ name:"a" },
{ name:"b" }
]
},
},
運行以后的效果如下:
那么現在的問題就是如何獲取數據了。
在官方文檔里我查到了fetch方法:
https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-network-data-request-0000000000626077
根據文檔的說法,我們首先要在index.js里導入fecth:
import fetch from '@system.fetch';
然后文檔里說了這個方法需要ohos.permission.INTERNET權限,于是我就去config.json里增加了權限。
在\DevEcoStudioProjects\MyApplication1\entry\src\main\config.json里找到module,在這個屬性下面增加:
"reqPermissions": [ { "name": "ohos.permission.INTERNET" }],
這個權限聲明部分其實還有很多需要增加的屬性,可以參考:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/security-permissions-guidelines-0000000000029886
這個其實跟安卓開發差不多。
不過這個fetch方法跟原生JS的fetch不太一樣
fetch.fetch({
url:"https://www.douban.com/j/app/radio/channels",
responseType: 'json',
success: function(response) {
console.info('response data:' + response.data);
console.info('response data:' + JSON.parse(response.data).channels);
},
fail: function(data, code) {
console.info('fail callback');
},
})
這個responseType據說設置成json就會返回對象,不過我測試下來并不會。
雖然你看我寫出來一副了然于胸的樣子,其實權限部分和這個fetch方法我一開始并不知道。
本來我以為可以直接用fetch,結果發現并不可以,后來突然想起來官方文檔里號稱用的是ES6語法,我就試了試import,誤打誤撞才發現原來需要自己導入fetch。
這時候我才去文檔里找到了相關的說明,才知道居然是fetch.fetch。
一開始也還是無法返回數據,我還以為華為的遠端調試不支持訪問外網,再看文檔才注意到權限。
設置了權限也無法訪問,又會去看文檔才注意到默認用https,要用http還需要另外設置。
這些都修改好了,就非常順利地返回了數據。
接下來的問題就是如何把數據渲染到界面上。
我把index.js里的onInit做了如下修改:
onInit() {
let me=this;
fetch.fetch({
url:"https://www.douban.com/j/app/radio/channels",
responseType: 'json',
success: function(response) {
console.info('response data:' + response.data);
me.data.items=JSON.parse(response.data).channels;
},
fail: function(data, code) {
console.info('fail callback');
},
})
}
重新運行之后(如果本地調試,是可以熱更新的,遠程調試需要重新運行):
所以說,直接修改data里的數據是可以導致重新渲染界面的。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。