首页 文章 精选 留言 我的

精选列表

搜索[AI 互动体验展],共10004篇文章
优秀的个人博客,低调大师

HDFS部署体验

目录 简单说明 重要的配置参数及配置选择 部署实践,参数配置修改记录 local machine, NameNode local machine, DataNode 192.168.1.101, DataNode 启动HDFS cluster 启动验证 hdfs shell创建文件 问题与解决 关闭HDFS cluster 结论 简单说明 下载hadoop distribution 有三个包: (区别是啥?) hadoop-x.y.z-site.tar.gz hadoop-x.y.z-src.tar.gz hadoop-x.y.z.tar.gz hadoop由不同的组件组成,不同组件有不同的daemon,每个daemon是独立的java process;配置daemon的启动参数,是通过环境变量实现 HDFS 在 etc/hadoop/hadoop-evn.sh 中配置 NameNode daemon: HDFS_NAMENODE_OPTS DataNode daemon: HDFS_DATANODE_OPTS Secondary NameNode daemon: HDFS_SECONDARYNAMENODE_OPTS YARN 在 etc/hadoop/yarn-evn.sh 中配置 ResourceManager daemon: YARN_RESOURCEMANAGER_OPTS NodeManager daemon: YARN_NODEMANAGER_OPTS WebAppProxy daemon: YARN_PROXYSERVER_OPTS MapReduce 在 etc/hadoop/mapred-evn.sh 中配置 MAP Reduce Job History Server daemon: MAPRED_HISTORYSERVER_OPTS hadoop全局配置,在系统文件(~/.bashrc)中配置 HADOOP_HOME: hadoop distribution的家目录,至少要配置 HADOOP_PID_DIR HADOOP_LOG_DIR HADOOP_HEAPSIZE_MAX 重要的配置参数及配置选择 所有节点都要配置 etc/hadoop/core-site.xml 示例配置位置:./share/doc/hadoop/hadoop-project-dist/hadoop-common/core-default.xml fs.defaultFS 配置HDFS中NameNode的URI io.file.buffer.size NameNode节点配置 etc/hadoop/hdfs-site.xml 示例配置位置:./share/doc/hadoop/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml dfs.namenode.name.dir dfs.hosts / dfs.hosts/excluded dfs.blocksize dfs.namenode.handler.count DataNode节点配置 etc/hadoop/hdfs-site.xml dfs.datanode.data.dir 部署实践,参数配置修改记录 local machine, NameNode system环境变量 export HADOOP_HOME="/home/jng/installed/hadoop/hadoop-3.2.0" export HADOOP_PID_DIR="/home/jng/installed/hadoop/hadoop_pid_dir" export HADOOP_LOG_DIR="/home/jng/installed/hadoop/hadoop_log_dir" etc/hadoop/core-size.xml fs.defaultFS <property> fs.defaultFShdfs://195.90.3.212:9988/The name of the default file system. A URI whosescheme and authority determine the FileSystem implementation. Theuri's scheme determines the config property (fs.SCHEME.impl) namingthe FileSystem implementation class. The uri's authority is used todetermine the host, port, etc. for a filesystem. </property> io.file.buffer.size <property> io.file.buffer.size4096The size of buffer for use in sequence files.The size of this buffer should probably be a multiple of hardwarepage size (4096 on Intel x86), and it determines how much data isbuffered during read and write operations. </property> etc/hadoop/hdfs-site.xml dfs.namenode.name.dir <property> <name>dfs.namenode.name.dir</name> <value>file:///home/jng/installed/hadoop/dfs_namenode_name_dir</value> <description>Determines where on the local filesystem the DFS name node should store the name table(fsimage). If this is a comma-delimited listof directories then the name table is replicated in all of thedirectories, for redundancy. </property> local machine, DataNode etc/hadoop/hdfs-site.xml dfs.datanode.data.dir <property> dfs.datanode.data.dirfile:///home/jng/installed/hadoop/dfs_datanode_data_dirDetermines where on the local filesystem an DFS data nodeshould store its blocks. If this is a comma-delimitedlist of directories, then data will be stored in all nameddirectories, typically on different devices. The directories should be taggedwith corresponding storage types ([SSD]/[DISK]/[ARCHIVE]/[RAM_DISK]) for HDFSstorage policies. The default storage type will be DISK if the directory doesnot have a storage type tagged explicitly. Directories that do not exist willbe created if local filesystem permission allows. </property> 192.168.1.101, DataNode system环境变量 export HADOOP_HOME="/home/mhb/installed/hadoop/hadoop-3.2.0" export HADOOP_PID_DIR="/home/mhb/installed/hadoop/hadoop_pid_dir" export HADOOP_LOG_DIR="/home/mhb/installed/hadoop/hadoop_log_dir" etc/hadoop/core-site.html fs.defaultFS <property> fs.defaultFShdfs://195.90.3.212:9988/The name of the default file system. A URI whosescheme and authority determine the FileSystem implementation. Theuri's scheme determines the config property (fs.SCHEME.impl) namingthe FileSystem implementation class. The uri's authority is used todetermine the host, port, etc. for a filesystem. </property> io.file.buffer.size <property> io.file.buffer.size4096The size of buffer for use in sequence files.The size of this buffer should probably be a multiple of hardwarepage size (4096 on Intel x86), and it determines how much data isbuffered during read and write operations. </property> etc/hadoop/hdfs-site.xml dfs.datanode.data.dir <property> dfs.datanode.data.dirfile:///home/mhb/installed/hadoop/dfs_datanode_data_dirDetermines where on the local filesystem an DFS data nodeshould store its blocks. If this is a comma-delimitedlist of directories, then data will be stored in all nameddirectories, typically on different devices. The directories should be taggedwith corresponding storage types ([SSD]/[DISK]/[ARCHIVE]/[RAM_DISK]) for HDFSstorage policies. The default storage type will be DISK if the directory doesnot have a storage type tagged explicitly. Directories that do not exist willbe created if local filesystem permission allows. </property> 启动HDFS cluster 首次启动HDFS cluster必须进行格式化 # 在namenode设备上执行(??) $ $HADOOP_HOME/bin/hdfs namenode -format <cluster_name> 启动NameNode # 在namenode设备上执行 $ $HADOOP_HOME/bin/hdfs --daemon start namenode 启动DataNode $ $HADOOP_HOME/bin/hdfs --daemon start datanode 可选一键启动 # 前提是同时满足: 1)etc/hadoop/workers文件被正确配置;2)NameNode设备与DataNode设备间无密码ssh访问已经配置完毕 $ $HADOOP_HOME/sbin/start-dfs.sh 启动验证 查看NameNode的web ui: http://ip:port default port is: 9870 查看DataNode的web ui: http://ip:port default port is: 9864 hdfs shell创建文件 从本地copy大尺寸文件到hdfs中,查看namenode、datanode的数据存储文件夹大小变化 copy文件前 local machine as NameNode的dfs.namenode.name.dir路径 [j@j dfs_namenode_name_dir]$ pwd /home/jng/installed/hadoop/dfs_namenode_name_dir [j@j dfs_namenode_name_dir]$ du -hs 2.1M . [j@j dfs_namenode_name_dir]$ local machine as DataNode的dfs.datanode.data.dir路径 [j@j dfs_datanode_data_dir]$ pwd /home/jng/installed/hadoop/dfs_datanode_data_dir [j@j dfs_datanode_data_dir]$ du -hs 44K . [j@j dfs_datanode_data_dir]$ 192.168.1.101 DataNode的dfs.datanode.data.dir路径 m@m:~/installed/hadoop/dfs_datanode_data_dir$ pwd /home/mhb/installed/hadoop/dfs_datanode_data_dir m@m:~/installed/hadoop/dfs_datanode_data_dir$ du -hs 44K . m@m:~/installed/hadoop/dfs_datanode_data_dir$ copy文件 # 在NameNode上操作 [j@j hadoop-3.2.0]$ pwd /home/jng/installed/hadoop/hadoop-3.2.0 [j@j hadoop-3.2.0]$ ls -lh ~/software/hadoop/hadoop-3.2.0.tar.gz -rw-r--r-- 1 jng jng 330M 2月 25 14:21 /home/jng/software/hadoop/hadoop-3.2.0.tar.gz [j@j hadoop-3.2.0]$ ./bin/hdfs dfs -moveFromLocal ~/software/hadoop/hadoop-3.2.0.tar.gz /tmp/ copy文件后 local machine as NameNode的dfs.namenode.name.dir路径 [j@j dfs_namenode_name_dir]$ pwd /home/jng/installed/hadoop/dfs_namenode_name_dir [j@j dfs_namenode_name_dir]$ du -hs 2.1M . [j@j dfs_namenode_name_dir]$ local machine as DataNode的dfs.datanode.data.dir路径 [j@j dfs_datanode_data_dir]$ pwd /home/jng/installed/hadoop/dfs_datanode_data_dir [j@j dfs_datanode_data_dir]$ du -hs 333M . [j@j dfs_datanode_data_dir]$ 192.168.1.101 as DataNode的dfs.dataanode.data.dir路径 m@m:~/installed/hadoop/dfs_datanode_data_dir$ pwd /home/mhb/installed/hadoop/dfs_datanode_data_dir m@m:~/installed/hadoop/dfs_datanode_data_dir$ du -hs 333M . m@m:~/installed/hadoop/dfs_datanode_data_dir$ 问题与解决 NameNode web UI 上查看 namenode-log 可能发现 WARN 形如:“WARN org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager: Unresolved datanode registration: hostname cannot be resolved (ip=192.168.1.101, hostname=192.168.1.101)“ ref: <https://blog.csdn.net/qqpy789/article/details/78189335> 修改文件 etc/hadoop/hdfs-site.xml 配置 dfs.namenode.datanode.registration.ip-hostname-check 取值为false <property> <name>dfs.namenode.datanode.registration.ip-hostname-check</name> <value>false</value> <description> If true (the default), then the namenode requires that a connectingdatanode's address must be resolved to a hostname. If necessary, a reverseDNS lookup is performed. All attempts to register a datanode from anunresolvable address are rejected. It is recommended that this setting be left on to prevent accidentalregistration of datanodes listed by hostname in the excludes file during aDNS outage. Only set this to false in environments where there is noinfrastructure to support reverse DNS lookup. </description> </property> 关闭HDFS cluster 关闭NameNode # 在NameNode设备上执行 $ $HADOOP_HOME/bin/hdfs --daemon stop namenode 关闭DataNode $ $HADOOP_HOME/bin/hdfs --daemon stop datanode 结论 HDFS可以独立与YARN存在并运行 即,不启动YARN,HDFS也能正常运行,至少通过HDFS shell是这样 HDFS的NameNode设备上可以同时运行一个DataNode

优秀的个人博客,低调大师

Kotlin初体验

距离kotlin成为Android一级开发语言已经一年了,这节将从零开始,实现kotlin的几个小知识点。 以下操作是在AndroidStudio3.0.1下完成的,如果是3.0以下版本的AndroidStudio,需要安装好kotlin插件才能使用Kotlin进行开发 Kotlin教程推荐 官网文档,黑马教程,《Kotlin for android developers》中文版翻译 相关代码已经上传到Github的KotlinPractice文件夹下了 创建项目: 在创建项目中勾选kolin支持后直接下一步即可 勾选kotlin支持 创建完项目后我们发现主类已经是使用了kotlin代码了,我们去project的build.gradle目录下可以看到 ext.kotlin_version = '1.1.51' kotlin //版本号 dependencies { classpath 'com.android.tools.build:gradle:3.0.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"//依赖 } 以及module下build.gradle的: apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' 实际上这就是我们刚才勾选kotlin后给我们自动生成的,如果我们想要在现有Java代码项目中使用kotlin,那么我们就需要手动的去添加这些依赖,或者使用方便的java代码转kotlin来进行配置,我们看到MainActivity默认已经是kotlin类了 /** * : AppCompatActivity() * :类名,表示继承于AppCompatActivity类 */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } 为TextView控件赋值: 我们在布局从添加一个TextView,id命名为text_01 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> </LinearLayout> 回到Activity,在activity的导包中添加这一行 import kotlinx.android.synthetic.main.activity_main.* 它的作用现在只要知道添加了这一行后我们就不需要再findViewById就可以了,activity_main的意思是Activity布局的包名。 import kotlinx.android.synthetic.main.activity_main.* /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") } } 运行程序,确实和我们想要的是一样的 设置按钮点击事件 我们再为布局添加3个button按钮 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> <Button android:id="@+id/btn_01" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮1" /> <Button android:id="@+id/btn_02" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮2" /> <Button android:id="@+id/btn_03" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮3" /> </LinearLayout> 回到Activity,让MainActivity类继承于View.OnClickListener接口,我们可以看到koltin继承接口是使用,号进行的,如果我们想要继承多个接口,只需要使用多个,分隔开来就行了 /** * : AppCompatActivity() :类名,表示继承于什么类 * ,View.OnClickListener, View.OnLongClickListener 表示继承于 View.OnClickListener 点击事件接口, View.OnLongClickListener 长按事件接口 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 然后就是我们熟悉的在点击事件里面使用switch找到对应控件的id了,只是在kotlin里面是使用when /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { Toast.makeText(this, "按钮1", Toast.LENGTH_LONG).show() } R.id.btn_02 -> { Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } 最后要注意,虽然我们通过import kotlinx.android.synthetic.main.activity_main.*使得不需要写控件的fndId,但是我们仍然是要写setOnClickListener(this)控件点击回调监听的 完整代码: import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Toast import kotlinx.android.synthetic.main.activity_main.* /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") // 设置控件的回调监听 init() } /** * 设置控件的回调监听 */ private fun init() { btn_01.setOnClickListener(this) btn_02.setOnClickListener(this) btn_03.setOnClickListener(this) } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { Toast.makeText(this, "按钮1", Toast.LENGTH_LONG).show() } R.id.btn_02 -> { Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 运行程序点击按钮后,出现了我们想要的吐司 实现网络请求 开始之前我们先在module下配置anko依赖,这是为了等下线程调度用的 module: dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' // kotlin插件anko implementation "org.jetbrains.anko:anko-common:0.10.4" } 然后实现我们的network()请求网络方法,最后不要忘了在AndroidManifest.xml下添加网络权限 <uses-permission android:name="android.permission.INTERNET" /> /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求 */ private fun network() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/k1" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() Log.d("tonjies", fore) } } 观察日志,我们可以看到确实已经获取了Json数据 这里写图片描述 Json数据解析 接下来我们进行json数据的解析,首先添加gson解析依赖 // goso解析 compile "com.google.code.gson:gson:2.4" 我们创建bean实体类包,在包下创建解析实体类Student,我们不需要像Java那样去生成get和set对象,因为这kotlin已经帮我们生成好啦! /** * Created by 舍长 on 2018/4/28. * 描述: 数据请求实体类 */ class Student { var name:String?=null var age:String?=null } 在按钮2的点击事件里面写一个gson方法,在gson方法里将网络请求到的数据转换成实体类,并且回到UI线程,显示在文字控件上 /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() gson(); } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求并使用gson解析数据 */ private fun gson() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() var fromJson: Student = Gson().fromJson(fore, Student::class.java) // 回到UI线程中去更新数据,这里的${属性名}是字符串模板,作用于Java的+属性名+相同 uiThread { txt_01.setText("学生的名字是${fromJson.name},年龄是${fromJson.age}") } } } 运行程序,点击按钮二,可以看到文字确实变成了我们想要的json数据:学习的名字是tonjies,年龄是18 这一小节的完整代码: 布局文件activity_main: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.administrator.kotlin.MainActivity"> <TextView android:id="@+id/txt_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试文本" /> <Button android:id="@+id/btn_01" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮1" /> <Button android:id="@+id/btn_02" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮2" /> <Button android:id="@+id/btn_03" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按钮3" /> </LinearLayout> MainActivity package com.example.administrator.kotlin import android.icu.lang.UCharacter.GraphemeClusterBreak.L import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.view.View import android.widget.Toast import com.example.administrator.kotlin.R.id.async import com.example.administrator.kotlin.bean.Student import com.google.gson.Gson import kotlinx.android.synthetic.main.activity_main.* import java.net.URL import org.jetbrains.anko.custom.async import org.jetbrains.anko.uiThread /** * : AppCompatActivity() :类名,表示继承与什么类 */ class MainActivity : AppCompatActivity(), View.OnClickListener, View.OnLongClickListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 为TextView设置值,koltin的语句后面是不需要;的,但是如果你加上也不会报错的 txt_01.setText("你好,世界") // 设置控件的回调监听 init() } /** * 设置控件的回调监听 */ private fun init() { btn_01.setOnClickListener(this) btn_02.setOnClickListener(this) btn_03.setOnClickListener(this) } /** * 重写OnClickListener接口的onClick方法 */ override fun onClick(p0: View?) { when (p0!!.id) { R.id.btn_01 -> { // 只进行网络请求 network(); } R.id.btn_02 -> { // 进行网路请求,并且进行json数据解析 Toast.makeText(this, "按钮2", Toast.LENGTH_LONG).show() gson(); } R.id.btn_03 -> { Toast.makeText(this, "按钮3", Toast.LENGTH_LONG).show() } } } /** * 网络请求并使用gson解析数据 */ private fun gson() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() var fromJson: Student = Gson().fromJson(fore, Student::class.java) // 回到UI线程中去更新数据,这里的${属性名}是字符串模板,作用于Java的+属性名+相同 uiThread { txt_01.setText("学生的名字是${fromJson.name},年龄是${fromJson.age}") } } } /** * 网络请求 */ private fun network() { // 声明要请求的网址,在kotlin中,var能声明一切类型,而后面的:String其实是可以不加的 var string: String = "http://www.wanandroid.com/tools/mockapi/2872/student" // 作用类似java在子线程中进行网络请求,但是async在kotlin中叫做协程 async() { val fore = URL(string).readText() Log.d("tonjies", fore) } } /** * 重写OnLongClickListener接口的onLongClick方法 */ override fun onLongClick(p0: View?): Boolean { return false } } 好了,这一小节就到这里啦!在学习的过程中,参考开源项目和巧妙使用Java代码转kotlin的快捷键是挺有用的

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册