three.js 原始碼註釋(五十九)objects/Mesh.js
俺也是剛開始學,好多地兒肯定不對還請見諒.
以下程式碼是THREE.JS 原始碼檔案中objects/Mesh.js檔案的註釋.
/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author jonobr1 / http://jonobr1.com/ */ /* ///Mesh物件,最終的網格物件,有高人把圖形學建模比作是製作燈籠,先用Geometry建立燈籠的框架,然後將材質material貼在框架上,最後形成的總體燈籠,就是Mesh物件.下面看一下Mesh物件的用法和具體實現. /// 用法:var geometry = new THREE.Geometry(1,1,1); //建立geometry物件(燈籠的框架), /// //有一下可選物件BoxGeometry,CircleGeometry,CubeGeometry,CylinderGeometry,DodecahedronGeometry,ExtrudeGeometry,IcosahedronGeometry, /// //LatheGeometry,OctahedronGeometry,ParametricGeometry,PlaneGeometry,PolyhedronGeometry,RingGeometry,ShapeGeometry,SphereGeometry, /// //TetrahedronGeometry,TextGeometry,TorusGeometry,TorusKnotGeometry,TubeGeometry /// var material = new THREE.Material({color: 0xffff00}); //建立材質物件(燈籠的表面) /// //有以下可選物件LineBasicMaterial,LineDashedMaterial,Material,MeshBasicMaterial,MeshDepthMaterial,MeshFaceMaterial, /// //MeshLambertMaterial,MeshNormalMaterial,MeshPhongMaterial,PointCloudMaterial,RawShaderMaterial,ShaderMaterial, /// //SpriteCanvasMaterial,SpriteMaterial /// var mesh = new THREE.Mesh(geometry, material); //建立mesh(燈籠)物件,並將geometry物件(燈籠的框架)和material物件(燈籠的表面)傳遞給mesh(燈籠)物件 /// scene.add(mesh); //將mesh(燈籠)新增到場景中. */ ///<summary>Mesh</summary> ///<param name ="geometry" type="THREE.Geometry">Geometry物件(燈籠的框架)</param> ///<param name ="material" type="THREE.Material">Material物件(材質物件)</param> ///<returns type="Mesh">返回Mesh物件</returns> THREE.Mesh = function ( geometry, material ) { THREE.Object3D.call( this ); //呼叫Object3D物件的call方法,將原本屬於Object3D的方法交給當前物件Mesh來使用. this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); //將引數geometry賦值給mesh物件的geometry屬性 this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); //將引數material賦值給mesh物件的material屬性 /* ///MorphTargets ///原文地址:http://www.tuicool.com/articles/rYzuuu ///先睹為快 /// ///MorphTargets允許物體發生變形。如果該物體的geometry有 $n$ 個頂點,那麼MorphTargets允許你再指定 $n$ 個, $2n$ 個, $3n$ 個甚至更多個頂點 ///(比如,$ p\cdot n$ 個),同時mesh物件提供一個數組morphTargetInfluences(公式中$ f_{j} $表示morphTargetInfluences[j]),具有 $p$ 個元素, ///每個元素取值在0-1之間。渲染這個物體的時候,某個頂點 $V_{i}$ 的位置其實變了,成了: /// ///$$V_{i}=V_{i}+\sum_{j=0}^{p}f_{j}\cdot (V_{j,i}-V_{i})$$ /// ///舉個簡單的例子,一個立方體有8個頂點, MorphTargets又指定了8個頂點,立方體的一個頂點為(1,1,1),而在 MorphTargets中與之對應的頂點為(2,2,2), ///那麼當 morphTargetInfluences[0]為0.5的時候,實際渲染的時候該頂點的位置就成了(1.5,1.5,1.5)。這樣做的好處是顯而易見的,你可以通過簡單地調整 /// morphTargetInfluences陣列來使物體形變,只要之前你設定好了。 /// ///向物體加入morphTargets的方法很簡單: /// ///var geometry = new THREE.CubeGeometry(100,100,100); /// var material = new THREE.MeshLambertMaterial({color:0xffffff, morphTargets:true}); /// /// var vertices = []; /// for(var i=0; i<geometry.vertices.length; i++) /// { /// var f = 2; /// vertices.push(geometry.vertices[i].clone()); /// vertices[i].x *= f; /// vertices[i].y *= f; /// vertices[i].z *= f; /// } /// geometry.morphTargets.push({name:'target0', vertices:vertices}); /// 在其他什麼地方(比如animate()或render()方法中)改變morphTargetInfluences,實在方便 /// ///var s = 0; ///function render() ///{ /// s += 0.03; /// mesh.morphTargetInfluences[0] = Math.abs(Math.sin(s)); /// ... ///} ///最關鍵的問題是,我相信,這個功能是通過著色器來完成的。我閱讀過一些簡單的著色器,因此我發現在著色器中完成這件事實在太合適了。 ///如果某個geometry有幾千甚至上萬個頂點,使用JavaScript逐個計算變形後頂點的位置會造成很大壓力,而顯示卡大規模平行計算的能力很適合處理這個任務 ///(畢竟每個頂點是獨立地)。 */ this.updateMorphTargets(); //更新目標變形,不影響geometry物件。 }; /************************************************* ****下面是Mesh物件的方法屬性定義,繼承自Object3D **************************************************/ THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); /* ///updateMorphTargets方法將geometry物件的morphTargets屬性複製到this.morphTargetInfluences屬性,不影響geometry物件本身。 */ ///<summary>updateMorphTargets</summary> ///<returns type="Mesh">返回新的Mesh物件</returns> THREE.Mesh.prototype.updateMorphTargets = function () { if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { //判斷geometry物件是否有目標變形陣列。 this.morphTargetBase = - 1; //給Mesh物件設定morphTargetBase屬性,並初始化為-1. this.morphTargetForcedOrder = []; //給Mesh物件設定morphTargetForcedOrder屬性陣列,初始化[]. this.morphTargetInfluences = []; //給Mesh物件設定morphTargetInfluences屬性陣列,初始化為[]. this.morphTargetDictionary = {}; //給Mesh物件設定morphTargetDictionary屬性,初始化為}{}. for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { //遍歷geometry物件 this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; //將geometry.morphTargets屬性陣列中的值,一一賦值給morphTargetDictionary[]屬性陣列。 } } }; /* ///getMorphTargetIndexByName方法通過引數name獲得儲存在morphTargetDictionary[]屬性陣列中的變形目標索引或者說是。 */ ///<summary>getMorphTargetIndexByName</summary> ///<param name ="name" type="String">MorphTarget儲存的名字</param> ///<returns type="Mesh">返回引數name所對應的頂點</returns> THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { if ( this.morphTargetDictionary[ name ] !== undefined ) { //如果morphTargetDictionary[name]屬性物件存在 return this.morphTargetDictionary[ name ]; //返回該物件。 } console.log( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); //提示使用者,該物件不存在。返回值是0. return 0; }; /* ///raycast方法用來獲得當前物件與射線(引數raycaster)的交點.raycaster.intersectObject會呼叫這個方法。主要是用來進行碰撞檢測, /// 在選擇場景中的物件時經常會用到,判斷當前滑鼠是否與物件重合用來選擇物件. /// NOTE:raycast方法中引數intersects引數用來儲存交點的集合,格式如下 /// intersects.push( { /// /// distance: distance, /// point: intersectionPoint, /// indices: [ a, b, c ], /// face: null, /// faceIndex: null, /// object: this /// /// } ); /// *////<summary>raycast</summary> ///<param name ="raycaster" type="THREE.Raycaster">射線物件</param> ///<param name ="intersects" type="ObjectArray">交點的集合</param> ///<returns type="ObjectArray">交點的集合</returns> THREE.Mesh.prototype.raycast = ( function () { var inverseMatrix = new THREE.Matrix4(); //宣告一個4x4矩陣,用來放置逆矩陣 var ray = new THREE.Ray(); //宣告全域性射線物件 var sphere = new THREE.Sphere(); //宣告全域性球體物件 var vA = new THREE.Vector3(); //宣告3維向量,vA var vB = new THREE.Vector3(); //宣告3維向量,vB var vC = new THREE.Vector3(); //宣告3維向量,vC return function ( raycaster, intersects ) { var geometry = this.geometry; // Checking boundingSphere distance to ray // 檢查geometry物件的球體邊界到射線的距離。 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( this.matrixWorld ); if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { //呼叫光線跟蹤的isIntersectionSphere方法,判斷geometry物件的球體邊界是否與射線相交。 return; //如果不相交,返回。 } // Check boundingBox before continuing //檢查geometry物件的立方體邊界到射線距離 inverseMatrix.getInverse( this.matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); if ( geometry.boundingBox !== null ) { if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { //呼叫光線跟蹤的isIntersectionBox方法,判斷geometry物件的立方體邊界是否與射線相交。 return; } } //如果geometry物件是BufferGeometry物件 if ( geometry instanceof THREE.BufferGeometry ) { var material = this.material; if ( material === undefined ) return; //如果沒有材質,返回 var attributes = geometry.attributes; var a, b, c; var precision = raycaster.precision; //精度因子 if ( attributes.index !== undefined ) { //如果bufferGeometry物件的attributes.index屬性不為undefined var indices = attributes.index.array; var positions = attributes.position.array; var offsets = geometry.offsets; if ( offsets.length === 0 ) { offsets = [ { start: 0, count: indices.length, index: 0 } ]; } for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { //根據定義bufferGeomentry存放的格式,遍歷attributes屬性.找到頂點資料儲存區域 var start = offsets[ oi ].start; var count = offsets[ oi ].count; var index = offsets[ oi ].index; for ( var i = start, il = start + count; i < il; i += 3 ) { //根據定義bufferGeomentry存放的格式,遍歷attributes屬性.找到頂點資料 a = index + indices[ i ]; b = index + indices[ i + 1 ]; c = index + indices[ i + 2 ]; vA.set( positions[ a * 3 ], positions[ a * 3 + 1 ], positions[ a * 3 + 2 ] ); vB.set( positions[ b * 3 ], positions[ b * 3 + 1 ], positions[ b * 3 + 2 ] ); vC.set( positions[ c * 3 ], positions[ c * 3 + 1 ], positions[ c * 3 + 2 ] ); if ( material.side === THREE.BackSide ) { //如果材質的side屬性為BackSide var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); //呼叫intersectTriangle方法判斷是否與引數VC,VB,VA組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數true,表示判斷背面 } else { var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); //呼叫intersectTriangle方法判斷是否與引數VA,VB,VC組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數,表示判斷正面 } if ( intersectionPoint === null ) continue; //如果沒有交點,跳出迴圈 intersectionPoint.applyMatrix4( this.matrixWorld ); //將非null的交點應用世界座標變換 var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); //計算射線原點到交點的距離 if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; //如果距離小於精度因子,或小於射線的近端,或大於射線的遠端,跳出迴圈 intersects.push( { //將相交的物件,頂點索引,距離,交點儲存到intersects屬性陣列中 distance: distance, //距離 point: intersectionPoint, //交點 indices: [ a, b, c ], //頂點在attribute屬性中的索引 face: null, //面 faceIndex: null, //面所在屬性陣列中的索引 object: this //物件 } ); } } } else { //如果bufferGeometry物件的attributes.index屬性為undefined var positions = attributes.position.array; for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) { //找到所有的頂點位置屬性 a = i; b = i + 1; c = i + 2; vA.set( positions[ j ], positions[ j + 1 ], positions[ j + 2 ] ); vB.set( positions[ j + 3 ], positions[ j + 4 ], positions[ j + 5 ] ); vC.set( positions[ j + 6 ], positions[ j + 7 ], positions[ j + 8 ] ); if ( material.side === THREE.BackSide ) { //如果材質的side屬性為BackSide var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true ); //呼叫intersectTriangle方法判斷是否與引數VC,VB,VA組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數true,表示判斷背面 } else { var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); //呼叫intersectTriangle方法判斷是否與引數VA,VB,VC組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數,表示判斷正面 } if ( intersectionPoint === null ) continue; //如果沒有交點,跳出迴圈 intersectionPoint.applyMatrix4( this.matrixWorld ); //將非null的交點應用世界座標變換 var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); //計算射線原點到交點的距離 if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; //如果距離小於精度因子,或小於射線的近端,或大於射線的遠端,跳出迴圈 intersects.push( { //將相交的物件,頂點索引,距離,交點儲存到intersects屬性陣列中 distance: distance, //距離 point: intersectionPoint, //交點 indices: [ a, b, c ], //頂點在attribute屬性中的索引 face: null, //面 faceIndex: null, //面所在屬性陣列中的索引 object: this //物件 } ); } } } else if ( geometry instanceof THREE.Geometry ) { //如果geometry物件是THREE.Geometry型別 var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? this.material.materials : null; var a, b, c, d; var precision = raycaster.precision; //精度因子 var vertices = geometry.vertices; for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { //遍歷geometry物件的所有面 var face = geometry.faces[ f ]; var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material; if ( material === undefined ) continue; //如果沒有材質,跳出迴圈 a = vertices[ face.a ]; b = vertices[ face.b ]; c = vertices[ face.c ]; if ( material.morphTargets === true ) { //如果有變性目標屬性 var morphTargets = geometry.morphTargets; var morphInfluences = this.morphTargetInfluences; vA.set( 0, 0, 0 ); vB.set( 0, 0, 0 ); vC.set( 0, 0, 0 ); for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { //將所有的頂點按照變形資料做變換 var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var targets = morphTargets[ t ].vertices; vA.x += ( targets[ face.a ].x - a.x ) * influence; vA.y += ( targets[ face.a ].y - a.y ) * influence; vA.z += ( targets[ face.a ].z - a.z ) * influence; vB.x += ( targets[ face.b ].x - b.x ) * influence; vB.y += ( targets[ face.b ].y - b.y ) * influence; vB.z += ( targets[ face.b ].z - b.z ) * influence; vC.x += ( targets[ face.c ].x - c.x ) * influence; vC.y += ( targets[ face.c ].y - c.y ) * influence; vC.z += ( targets[ face.c ].z - c.z ) * influence; } vA.add( a ); vB.add( b ); vC.add( c ); a = vA; b = vB; c = vC; } if ( material.side === THREE.BackSide ) { //如果材質的side屬性為BackSide var intersectionPoint = ray.intersectTriangle( c, b, a, true ); //呼叫intersectTriangle方法判斷是否與引數VC,VB,VA組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數true,表示判斷背面 } else { var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); //呼叫intersectTriangle方法判斷是否與引數VA,VB,VC組成的Triangle三角形物件相交,如果相交返回交點.如果不想交返回null,這裡最後一個引數,表示判斷正面 } if ( intersectionPoint === null ) continue; //如果沒有交點,跳出迴圈 intersectionPoint.applyMatrix4( this.matrixWorld ); //將非null的交點應用世界座標變換 var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); //計算射線原點到交點的距離 if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; //如果距離小於精度因子,或小於射線的近端,或大於射線的遠端,跳出迴圈 intersects.push( { distance: distance, //距離 point: intersectionPoint, //交點 face: face, //面 faceIndex: f, //面索引 object: this //物件 } ); } } }; }() ); /*clone方法 ///clone方法克隆一個Mesh網格物件. */ ///<summary>clone</summary> ///<param name ="object" type="Object3D">接收克隆的Object3D物件</param> ///<param name ="recursive" type="boolean">是否對子物件一一進行克隆</param> ///<returns type="Ray">返回Mesh網格物件.</returns> THREE.Mesh.prototype.clone = function ( object, recursive ) { if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); THREE.Object3D.prototype.clone.call( this, object, recursive ); //繼承Object3D的clone方法 return object; //返回Mesh網格物件. };
以下程式碼是THREE.JS 原始碼檔案中objects/Mesh.js檔案的註釋.
相關推薦
three.js 原始碼註釋(五十九)objects/Mesh.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中objects/Mesh.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / htt
three.js 原始碼註釋(四十九)Material /MeshNormalMaterial.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Material/MeshNormalMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * * para
three.js 原始碼註釋(五十一)Material /MeshDepthMaterial.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中materials/MeshDepthMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author
three.js 原始碼註釋(二十二)Core/Object3D.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Core/Object3D.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author mikael emting
three.js 原始碼註釋(二十七)Core/BufferGeometry.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Core/BufferGeometry.js檔案的註釋. /** * @author alteredq / http://alteredqualia.com/ */ /* //
three.js 原始碼註釋(四十二)Light/AreaLight.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Light/AreaLight.js檔案的註釋. /** * @author MPanknin / http://www.redplant.de/ * @author alte
three.js 原始碼註釋(三十四)Texture/Texture.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Texture/Texture.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author alteredq /
three.js 原始碼註釋(五十)Material /MeshPhongMaterial.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中materials/MeshPhongMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author
three.js 原始碼註釋(八十四)extras/geometries/ParametricGeometry.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中extras/geometries/ParametricGeometry.js檔案的註釋. /** * @author zz85 / https://github.com/zz8
three.js 原始碼註釋(七十八)extras/geometries/IcosahedronGeometry.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中extras/geometries/IcosahedronGeometry.js檔案的註釋. /** * @author timothypratley / https://git
three.js 原始碼註釋(六十)objects/Line.js
俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中objects/Line.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ */ /* ///Line物件,建立一條線,或者
Linux學習總結(五十九)shell 腳本3-for while 循環
shell 循環 for while 1 for 循環 語法: for 變量名 in 條件;do ...; done舉例1 #!/bin/bash sum=0 for i in `seq 1 100`;do sum=$[$sum+$i] done echo $sum 舉例2找到/123 目錄
ElasticSearch最佳入門實踐(五十九)基於scoll技術滾動搜尋大量資料
如果一次性要查出來比如10萬條資料,那麼效能會很差,此時一般會採取用scoll滾動查詢,一批一批的查,直到所有資料都查詢完處理完 使用scoll滾動搜尋,可以先搜尋一批資料,然後下次再搜尋一批資料,以此類推,直到搜尋出全部的資料來 scoll搜尋會在第一次搜尋的
Java程式設計師從笨鳥到菜鳥(五十九)JSON
stringify() 和 parse() 的區別 序列化 stringify():將 javascript 物件序列化為 Json 字串 反序列化 parse(): 將 Json 字串解析為原生的 JavaScript 物件
Java基礎(五十九)-集合工具類(Java類集框架)
1:Stack棧 棧是一種先進後出的資料結構。例如:在文字編輯器上都有撤銷功能,那麼每次使用的時候,最後一次的編輯操作永遠是最先撤銷的,那麼這個功能就是利用棧來實現的,棧的基本操作形式如下。 案例:實現棧的操作 import java.util.Stack;
Android原始碼解析(二十九)-->應用程式返回按鍵執行流程
從這篇文章中我們開始分析android系統的事件分發流程,其實網上已經有了很多關於android系統的事件分發流程的文章,奈何看了很多但是印象還不是很深,所以這裡總結一番。 android系統的事件分發流程分為很多部分: Native層 –> V
OpenCV學習筆記(五十九)——marker檢測識別"Master OpenCV"chp.2
第二章原本是講如何將基於標定的增強現實在ios平臺實現,包括以下4個方面: 1、在ios平臺建立opencv工程 2、Marker檢測識別 3、攝像機標定及Marker姿態估計 4、在Marker基礎上渲染一個3維虛擬物體 這裡面第一部分是IOS平臺的開發,我不是太關注,略
Java程式設計師從笨鳥到菜鳥之(五十九)細談Hibernate(十)hibernate查詢排序和元件對映
上一篇: 在實際開發過程中,有很多使用者需要時要把查詢出來的結果進行排序顯示,而不是在資料庫裡面那樣順序混亂那樣的顯示,這樣的話我們不得不要對資料進行排序了,hibernate對資料排序提供了很好的支援,hibernate提供了兩種對查詢到得資料結
Java開發筆記(五十九)Java8之後的擴展接口
com 完整 不遠 urn 遊泳 java8 調用接口 基本 中國 前面介紹了接口的基本用法,有心的朋友可能註意到這麽一句話“在Java8以前,接口內部的所有方法都必須是抽象方法”,如此說來,在Java8之後,接口的內部方法也可能不是抽象方法了嗎?之所以Java8對接口的定
Coding and Paper Letter(五十九)
開發十年,就只剩下這套架構體系了! >>>