Fork me on GitHub

编程常用命令

1.redis

(1)启动:
1
2
3
cd /usr/local/redis

./bin/redis-server ./redis.conf
(2)查看
1
ps -ef | grep redis
(3)启动客户端:
1
2
3
4
5
cd /usr/local/redis

./bin/redis-cli

./bin/redis-cli -h 192.168.31.141
(4)插入数据:
1
lpush uid:1 1129:2.0 1172:4.0 1263:2.0 1287:2.0 1293:2.0 1339:3.5 1343:2.0 1371:2.5
(5)查询数据:
1
lrange uid:1 0 20

2.Mongodb

(1)启动
1
2
3
cd /usr/local/mongodb

./bin/mongod -config ./data/mongodb.conf
(2)关闭:
1
2
3
cd /usr/local/mongodb

./bin/mongod -shutdown -config ./data/mongodb.conf

3.kafka

(1)启动
1
bin/kafka-server-start.sh config/server.properties &
(2)关闭
1
bin/kafka-server-stop.sh stop
(3)生产消息
1
2
3
bin/kafka-console-producer.sh --broker-list bigdata11:9092 --topic first

>hello world
(4)消费消息
1
2
3
bin/kafka-console-consumer.sh --zookeeper bigdata11:2181 --from-beginning --topic first

bin/kafka-console-consumer.sh --bootstrap-server 192.168.31.141:9092 --topic first
(5)查看所有topic
1
bin/kafka-topics.sh --zookeeper bigdata13:2181 --list

4.HBase

(1)启动方式一
1
2
3
bin/hbase-daemon.sh start master

bin/hbase-daemon.sh start regionserver
(2)启动方式二
1
bin/start-hbase.sh
(3)停止服务
1
bin/stop-hbase.sh

5.Spark

(1)启动
1
sbin/start-all.sh
(2)停止
1
sbin/stop-all.sh

6.ZooKeeper

(1)分别启动
1
bin/zkServer.sh start
(2)分别停止
1
bin/zkServer.sh stop

7.Hive

(1)启动
1
bin/hive
(2)退出hive
1
2
3
quit;

exit;
(3).“-e”不进入hive的交互窗口执行sql语句
1
bin/hive -e "select id from student;"
(4).“-f”执行脚本中sql语句,执行文件中的sql语句
1
bin/hive -f /opt/module/datas/hive.sql
(5).在hive cli命令窗口中如何查看hdfs文件系统
1
dfs -ls /;
(6).在hive cli命令窗口中如何查看linux本地系统
1
! ls /opt/module/datas;

利用FRP实现内网穿透

情况:
自己有两台电脑,一台16G内存的Dell,和一台8G内存的MacBook Pro,因为自己学的是大数据开发,所以需要搭建大数据集群,因此在MacBook Pro开发的话内存太小了,既要用虚拟机搭建大数据集群,又要用IDEA开发的话,内存是肯定不够的,所以之前是在Dell上面创建虚拟机,搭建大数据集群,然后再在MacBook Pro上开发,因为虚拟机使用的桥接法上网,Macbook Pro和Dell又在同一个局域网里,所以还可以,但是如果需要离开,区别的地方的话,自己就需要带两台电脑了,太沉了,所以就打算用内网穿透,让MacBook 在外网,也可以访问Dell里的虚拟机

一.介绍

1.FRP介绍:

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。

2.FRP项目地址:

https://github.com/fatedier/frp

3.环境:

(1)带外网IP的云主机-腾讯云:49.xxx.xxx.xx
(2)内网的CentOS7(Windows搭建的虚拟机):192.168.0.161

二.搭建过程

1.在云主机上搭建FRP服务端:
(1)下载对应的FTP包:

拷贝链接

下载

1
2
3
cd /mnt

wget https://github.com/fatedier/frp/releases/download/v0.31.1/frp_0.31.1_linux_386.tar.gz
(2).解压:
1
tar -zxvf frp_0.31.1_linux_386.tar.gz
(3).重命名:
1
mv frp_0.31.1_linux_386 frp 

(4).修改配置文件(服务端)
1
2
3
cd ftp

vi frps.ini

修改内容:

1
2
3
#frps.ini
[common]
bind_port = 7000

frpc.ini

(5)关闭防火墙,或者打开6000端口:
(6)运行
1
./frps -c ./frps.ini

2.在内网CentOS7虚拟机配置FRP客户端

(1)下载:
1
2
3
cd /mnt

wget https://github.com/fatedier/frp/releases/download/v0.31.1/frp_0.31.1_linux_386.tar.gz

(2)解压,重命名:
1
2
3
tar -zxvf frp_0.31.1_linux_386.tar.gz

mv frp_0.31.1_linux_386 frp
(3)修改客户端配置文件frpc.ini
1
2
3
cd /mnt/frp

vi frpc.ini

修改内容:

1
2
3
4
5
6
7
8
9
10
# frpc.ini
[common]
server_addr = 49.x.x.x
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
  • server_addr填写的是云服务器IP
  • remote_port 填写的是远程访问的端口号
(4)启动frpc
1
./frpc -c ./frpc.ini

image.png

3.测试:

1
2

线程

一.线程

1.创建多线程程序的第一种方式:创建Thread类的子类

(1)实现步骤
  • 创建一个Thread类的子类
  • 在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么?)
  • 在创建Thread类的子类对象
  • 调用Thread类中的start方法,开启新的线程,执行run方法

2.Thread类

(1)构造方法
1
2
3
4
public Thread();      //分配一个新的线程对象
public Thread(String name); //分配一个指定名字的新线程对象
public Thread(Runnable target); //分配一个带有指定目标的新的线程对象
public Thread(Runnable target,String name); //分配一个带有指定目标的新线程对象并指定名字
(2)常用方法
1
2
3
4
5
public String getName();		//获取当前线程的名称
public void start(); //导致此线程开始执行,Java虚拟机调用此线程的run方法
public void run(); //此线程要执行的任务在此定义
public static void sleep(long millis); //使当前正在执行的线程以指定的毫秒数暂停
public static Thread currentThread(); //返回对当前正在执行的线程对象的引用
(3)设置线程的名称
  • 使用Thread类中的方法setName(名字)
      void setName(String name) 改变线程名称,使之与参数 name 相同。
    
  • 创建一个带参数的构造方法,参数传递线程的名称;调用父类的带参构造方法,把线程名称传递给父类,让父类(Thread)给子线程起一个名字
      Thread(String name) 分配新的 Thread 对象。
    

3.创建线程方式二:实现Runnable接口

(1)概念
  • Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。
(2)实现步骤:
  • 创建一个Runnable接口的实现类
  • 在实现类中重写Runnable接口的run方法,设置线程任务
  • 创建一个Runnable接口的实现类对象
  • 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
  • 调用Thread类中的start方法,开启新的线程执行run方法
(3)实现Runnable接口创建多线程程序的好处:

a.避免了单继承的局限性

  • 一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类
  • 实现了Runnable接口,还可以继承其他的类,实现其他的接口

b.增强了程序的扩展性,降低了程序的耦合性(解耦)

  • 实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
  • 实现类中,重写了run方法:用来设置线程任务
  • 创建Thread类对象,调用start方法:用来开启新线程

异常

1.异常的特点

(1)java.Lang.Throwable:类是java语言中所有错误或异常的超类
(2)Exception:
  • 编译期异常,进行编译(写代码)java程序时出现的问题
  • RuntimeException:运行期异常,java程序在运行过程中出现的问题
  • 异常就相当于程序得了一个小毛病(感冒,发烧),把异常处理掉,程序可以继续执行(吃点药,继续工作)
(3)Error:错误
  • 错误就相当于程序得了一个无法治愈的病(艾滋),必须修改源代码,程序才能继续执行

2.异常的处理

3.throw关键字

(1)作用:可以使用throw关键字在指定的方法中抛出指定的异常
(2)使用格式:throw new xxxException(“异常产生的原因”);
(3)注意:
  • throw关键字必须写在方法的内部
  • throw关键字后边new的对象必须是Exception或者Exception的子类对象
  • throw关键字抛出指定的异常对象,就必须处理这个异常对象:
  • thorw关键字后边创建的事RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
  • throw关键字后边创建的是编译异常,我们就必须处理这个异常,要么throws,要么try…catch

4.Objects类中的静态方法

(1)代码源码:
1
2
3
4
5
6
7
8
public static <T> requireNoNull(T obj);    //查看指定引用对象不是null

public static <T> requireNoNull(T obj){
if(obj == null){
throw new NullPointerException();
}
return obj;
}
(2)用法:
1
2
3
4
5
6
7
8
9
10
11
public class ObjectsDemp {
public static void main(String[] args) {
demo01(null);
}

private static void demo01(Object obj) {

//Objects.requireNonNull(obj);
Objects.requireNonNull(obj,"传递对象的值是null");
}
}

5.Throws声明异常

(1)throws关键字:异常处理的第一种方式,交给别人处理
(2)作用:
  • 当方法内部抛出异常对象的时候,我们必须处理这个异常
  • 可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,交给别人处理),最终交给JVM处理(中断)
(3)使用格式:在方法声明时使用
1
2
3
4
修饰符 返回值类型 方法名(参数列表) throws{
throw new XXXException("产生原因");
...
}
(4)注意:
  • throws关键字必须写在方法的声明处
  • throws关键字后边声明的异常必须是Exception或Exception的子类
  • 方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常,如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
  • 调用了一个声明抛出的方法,我们就必须处理声明的异常,要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM,要么try…catch自己处理异常

6.try…catch:异常处理的第二种方式 自己处理异常

(1)格式:
1
2
3
4
5
6
7
8
9
10
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){

}
(2)注意:
  • try中可能抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
  • 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码
  • 如果try中没有产生异常,就不会执行catch中的异常处理逻辑,执行完try中的代码,继续执行try…catch之后的代码

7.Throwable类中定义了3个异常处理的方法

(1)代码
1
2
3
String getMessage();  //返回此throwable的简短描述
String toString(); //返回此throwable的详细消息字符串
void printStackTrace(); //JVM打印异常对象,默认此方法,打印的异常信息是最全面的

8.异常的注意事项

(1)多个异常使用捕获该如何处理
  • 多个异常分别处理
  • 多个异常一次捕获,多次处理
  • 多个异常一次捕获,一次处理
(2)多个异常一次捕获,多次处理-注意:
  • catch里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则会报错
(3)运行时一次被抛出可以不处理,即不捕获也不声明抛出
(4)如果finally有return语句,永远返回finally中的结果,避免该情况
(5)如果父类抛出了多个异常,子类覆盖父类的方法时,只能抛出相同的异常或者是它的子类
(6)父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出
(7)在try/catch后可以追加finally代码块,其中的代码一定会执行,通过用于资源回收

9.自定义异常

(1)自定义异常类:java提供的异常类,不够我们使用,需要自己定义一些异常类
(2)格式:
1
2
3
4
public class XXXException extends Exception|RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
(3)注意:
  • 自定义异常类一般都是以Exception结尾,说明该类是一个异常类
  • 自定义异常类,必须得继承Exception或者RuntimeException
  • 继承Exception,那么该自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么t r y…catch
  • 继承RuntimeException,那么该自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断)

10.finally代码块

(1)格式:
1
2
3
4
5
6
7
8
9
10
11
12
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){

}finally{
无论是否出现异常都会执行
}
(2)注意:
  • finally不能单独使用,必须和try一起使用
  • finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要是否(IO)

Map

1.Map<key,value>集合的特点

  • Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
  • Map集合中的元素,key和value的数据类型可以相同,也可以不同
  • Map集合中的元素,key是不允许重复的,value是可以重复的
  • Map集合中的元素,key和value是一一对应的

2.HashMap

(1)HashMap集合的特点:
  • HashMap底层是哈希表:查询的速度特别快:JDK1.8之前:数组+单向链表-JDK1.8之后:数组+单向链表/红黑树(链表的长度超过8):提高查询的速度
  • HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致

3.LinkedHashMap

(1).LinkedHashMap的特点

  • LinkedHashMap继承自HashMap
  • LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
  • LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的

4.Map中的常用方法

(1)常用方法
1
2
3
4
5
6
public V put(K key,V value);       //	把指定的键与指定的值添加到Map集合中
public V remove(Object key); //把指定的键所对应的键值对元素在Map集合中删除,返回被删除元素的值
public V get(Object key); //根据指定的键,在Map集合中获取对应的值
boolean containsKey(Object key); //判断集合中是否包含指定的键
public Set<K> keySet(); //获取Map集合中所有的键,存储到Set集合中
public Set<Map.Entry<K,V>> entrySet(); //获取到Map集合中所有的键值对对象的集合(Set集合)

5.Map.Entry<K,V>:

(1)在Map接口中有一个内部接口Entry
(2)作用:
  • 当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值(键值对对象,键与值的映射关系)–>结婚证
(3)entrySet():把Map集合内部的多个Entry对象取出来存储到一个Set集合中
1
2
格式
Set<Map.Entry<K,V>> entrySet()

6.Map集合的遍历方法

(1)Map集合的第一种遍历方式:通过键找值
1
2
3
4
5
6
Map集合中的方法:
Set<K> keySet() 返回此映射中包含的键的Set视图
实现步骤:
1.使用Map集合中的keySet()方法,把Map集合所有的key取出来,存储到一个Set集合中
2.遍历Set集合,获取Map集合中的每一个key
3.通过Map集合中的方法get(key),通过key找到value

示例
Map02KeySetDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Map02KeySetDemo {

public static void main(String[] args) {
demo01();
}

/**
* 使用keySet方法遍历Map
*/
private static void demo01() {
Map<String,Integer> map = new HashMap<>();
map.put("林志玲",18);
map.put("吴亦凡",38);
map.put("林志颖",28);
map.put("赵忠祥",48);
map.put("成龙",57);

Set<String> set = map.keySet();

for(String k:set){
Integer value = map.get(k);
System.out.println(k+"="+value);
}

}
}

(2)Map集合的第二种遍历方式:使用Entry对象遍历
1
2
3
4
5
6
7
Map集合中的方法:
Set <Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的Set视图

实现步骤:
1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
2.遍历Set集合,获取每一个Entry对象
3.视图Entry对象中的方法getKey()和getValue()获取键和值

示例
Map03EntrySetDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Map03EntrySetDemo {

public static void main(String[] args) {
demo01();
}

private static void demo01() {
Map<String,Integer> map = new HashMap<>();
map.put("林志玲",18);
map.put("吴亦凡",38);
map.put("林志颖",28);
map.put("赵忠祥",48);
map.put("成龙",57);

Set<Map.Entry<String,Integer>> set = map.entrySet();

System.out.println("========使用迭代器遍历=========");
Iterator<Map.Entry<String,Integer>> it = set.iterator();

while(it.hasNext()){
Map.Entry<String,Integer> m = it.next();
String K = m.getKey();
Integer V = m.getValue();

System.out.println(K+"="+V);
}
System.out.println("========增强for循环遍历=========");
for (Map.Entry<String,Integer> m:set) {
String Key = m.getKey();
Integer Value = m.getValue();
System.out.println(Key+"="+Value);
}
}

7.HashMap存储自定义类型的键值

(1)Map集合保证key是唯一的
  • 作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
(2)示例

a.HashMap01Demo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class HashMap01Demo {
public static void main(String[] args) {
//demo01();
demo02();
}

/**
* HashMap存储自定义类型键值
* key:Person类型-Person类必须重写hashCode方法与equals方法,以保证key唯一
* value:String类型-可以重复
*/
private static void demo02() {
HashMap<Person,String> map = new HashMap<>();
map.put(new Person("张三",19),"北京");
map.put(new Person("李四",22),"南京");
map.put(new Person("王五",99),"重庆");
map.put(new Person("赵六",38),"上海");
map.put(new Person("张三",19),"天津");

Set<Map.Entry<Person, String>> entrys = map.entrySet();
for (Map.Entry<Person,String> en:entrys) {
Person person = en.getKey();
String value = en.getValue();
System.out.println(person+"-->"+value);
}

}

/**
* HashMap存储自定义类型键值
* key:String类型 -String类型重写HashCode和equals方法,可以保证唯一
* value:Person类型 - value可以重复(同名同年龄的人视为同一个)
*/
private static void demo01() {
HashMap<String,Person> map = new HashMap<>();

map.put("北京",new Person("张三",19));
map.put("南京",new Person("李四",17));
map.put("重庆",new Person("王五",22));
map.put("上海",new Person("赵六",30));
map.put("天津",new Person("胡八",18));

Set<String> set = map.keySet();
for (String s:set) {
Person value = map.get(s);
System.out.println(s+"-->"+value);
}
}
}

b.Person.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}

8.LinkedHashMap

(1)LinkedHashMap继承自HashMap
(2)LinkedHashMap接口的哈希表和链表实现,具有可预知的迭代顺序
(3)底层原理:哈希表+链表(记录元素的顺序)

9.HashTable

(1)HashTable特点
  • HashTable继承自Map<K,V>接口
  • HashTable:底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
  • HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程集合,速度快
  • HashMap集合:可以存储null值,null键
  • HashTable集合:不能存储null值,null键
  • HashTable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
  • HashTable的子类Properties依然活跃在历史舞台
  • Properties集合是一个唯一和IO流相结合的集合

Collections集合工具类

1.常用功能

1
2
3
4
public static <T> boolean addAll(Collection<T> c,T...elements);  //往集合中添加一些元素
public static void shuffle(List<?> list); //打乱集合的顺序
public static <T> void sort(List<T> list); //将集合中元素按照默认规则排序
public static <T> void sort(List<T> list,Comparator<? super T>); //将集合中元素按照指定规则排序

2.注意

(1)sort(List list)使用前提:
  • 被排序的集合里面存储的元素,必须实现comparable,重写接口中的方法compareTo定义排序的规则
(2)Comparable接口的排序规则:
  • 自己(this)-参数 :升序
  • 参数-自己(this):降序
(3)Comparator和Comparable的区别
  • Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较的规则compareTo方法
  • Comparator:相当于找一个第三方的裁判,比较两个对象
(4)Comparator的排序规则:
  • o1-o2:生序
  • o2-o1:降序

3.示例

(1).CollectionsAPI.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class CollectionsAPI {
public static void main(String[] args) {
//demo01();
//demo02();
//demo03();
demo04();
}

/**
* Collections工具类之sort排序另一种方法
*/
private static void demo04() {
ArrayList<Integer> Lisa = new ArrayList<>();
Lisa.add(1);
Lisa.add(4);
Lisa.add(2);
Lisa.add(3);
Lisa.add(9);
Lisa.add(8);
System.out.println("排序前:lisa"+Lisa);

Collections.sort(Lisa, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//生序
//return o1-o2;
//降序
return o2-o1;
}
});
System.out.println("排序后:lisa"+Lisa);

ArrayList<Student> stu = new ArrayList<>();
stu.add(new Student("迪丽热巴",18));
stu.add(new Student("古力娜扎",20));
stu.add(new Student("胡歌",17));
stu.add(new Student("胡歌",18));
System.out.println("排序前的stu:"+stu);

Collections.sort(stu, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int result = o1.getAge()-o2.getAge();
if(result==0){
result = o1.getName().charAt(0)-o2.getName().charAt(0);
}
return result;
}
});
System.out.println("排序前后stu:"+stu);
}

/**
* Collections工具类sort排序之自定义类型的排序
* 自己(this)-参数 :升序
* 参数-自己(this):降序
*/
private static void demo03() {
ArrayList<Person> person = new ArrayList<>();
person.add(new Person("张三",18));
person.add(new Person("李四",20));
person.add(new Person("王武",15));
System.out.println("排序前的集合:person"+person);

Collections.sort(person);
System.out.println("排序后的集合:person"+person);
}

/**
* Collections工具类之排序
*/
private static void demo02() {
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(4);
list1.add(2);
list1.add(3);
list1.add(9);
list1.add(8);
System.out.println("排序前的集合:list1"+list1);

Collections.sort(list1);
System.out.println("排序后的集合:list1"+list1);
}

/**
* Collections工具类的单次加入多个元素与打乱集合顺序
*/
private static void demo01() {
ArrayList<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");
list1.add("c");
list1.add("d");
list1.add("e");
System.out.println("多次加入单个元素:list1"+list1);

//添加多个元素
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"a","b","c","d","e");
System.out.println("单次加入多个元素:list2"+list2);

//打乱顺序
Collections.shuffle(list1);
System.out.println("打乱顺序后的集合:list1"+list1);

}
}
(2).Person.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Person implements Comparable<Person>{
private String name;
private int age;
@Override
public int compareTo(Person o) {
/*年龄生序排列*/
return this.getAge()-o.getAge();

//return 0;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setAge(int age) {
this.age = age;
}
}
(3).Student.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Student {
private String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

ffmpeg合并视频

1.方法一:FFmpeg concat协议

1
ffmpeg -i "concat:input1.mp4|input2.mp4|input3.mp4" -c copy output.mp4

2.方法二:FFmpeg concat分离器

新建文件file.txt

1
2
3
file 'input1.mp4'
file 'input2.mp4'
file 'input3.mp4'

然后

1
ffmpeg -f concat -i file.txt -c copy output.mp4

ffmpeg参数

1.通用选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-L license
-h 帮助
-fromats 显示可用的格式,编解码的,协议的...
-f fmt 强迫采用格式fmt
-I filename 输入文件
-y 覆盖输出文件
-t duration 设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持
-ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持
-title string 设置标题
-author string 设置作者
-copyright string 设置版权
-comment string 设置评论
-target type 设置目标文件类型(vcd,svcd,dvd) 所有的格式选项(比特率,编解码以及缓冲区大小)自动设置,只需要输入如下的就可以了:ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
-hq 激活高质量设置
-itsoffset offset 设置以秒为基准的时间偏移,该选项影响所有后面的输入文件。该偏移被加到输入文件的时戳,定义一个正偏移意味着相应的流被延迟了 offset秒。 [-]hh:mm:ss[.xxx]的格式也支持

2.视频选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-b bitrate 设置比特率,缺省200kb/s
-r fps 设置帧频 缺省25
-s size 设置帧大小 格式为WXH 缺省160X128.下面的简写也可以直接使用:
Sqcif 128X96 qcif 176X144 cif 252X288 4cif 704X576
-aspect aspect 设置横纵比 4:3 16:9 或 1.3333 1.7777
-croptop size 设置顶部切除带大小 像素单位
-cropbottom size –cropleft size –cropright size
-padtop size 设置顶部补齐的大小 像素单位
-padbottom size –padleft size –padright size –padcolor color 设置补齐条颜色(hex,6个16进制的数,红:绿:兰排列,比如 000000代表黑色)
-vn 不做视频记录
-bt tolerance 设置视频码率容忍度kbit/s
-maxrate bitrate设置最大视频码率容忍度
-minrate bitreate 设置最小视频码率容忍度
-bufsize size 设置码率控制缓冲区大小
-vcodec codec 强制使用codec编解码方式。如果用copy表示原始编解码数据必须被拷贝。
-sameq 使用同样视频质量作为源(VBR)
-pass n 选择处理遍数(1或者2)。两遍编码非常有用。第一遍生成统计信息,第二遍生成精确的请求的码率
-passlogfile file 选择两遍的纪录文件名为file

3.高级视频选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-g gop_size 设置图像组大小
-intra 仅适用帧内编码
-qscale q 使用固定的视频量化标度(VBR)
-qmin q 最小视频量化标度(VBR)
-qmax q 最大视频量化标度(VBR)
-qdiff q 量化标度间最大偏差 (VBR)
-qblur blur 视频量化标度柔化(VBR)
-qcomp compression 视频量化标度压缩(VBR)
-rc_init_cplx complexity 一遍编码的初始复杂度
-b_qfactor factor 在p和b帧间的qp因子
-i_qfactor factor 在p和i帧间的qp因子
-b_qoffset offset 在p和b帧间的qp偏差
-i_qoffset offset 在p和i帧间的qp偏差
-rc_eq equation 设置码率控制方程 默认tex^qComp
-rc_override override 特定间隔下的速率控制重载
-me method 设置运动估计的方法 可用方法有 zero phods log x1 epzs(缺省) full
-dct_algo algo 设置dct的算法 可用的有 0 FF_DCT_AUTO 缺省的DCT 1 FF_DCT_FASTINT 2 FF_DCT_INT 3 FF_DCT_MMX 4 FF_DCT_MLIB 5 FF_DCT_ALTIVEC
-idct_algo algo 设置idct算法。可用的有 0 FF_IDCT_AUTO 缺省的IDCT 1 FF_IDCT_INT 2 FF_IDCT_SIMPLE 3 FF_IDCT_SIMPLEMMX 4 FF_IDCT_LIBMPEG2MMX 5 FF_IDCT_PS2 6 FF_IDCT_MLIB 7 FF_IDCT_ARM 8 FF_IDCT_ALTIVEC 9 FF_IDCT_SH4 10 FF_IDCT_SIMPLEARM
-er n 设置错误残留为n 1 FF_ER_CAREFULL 缺省 2 FF_ER_COMPLIANT 3 FF_ER_AGGRESSIVE 4 FF_ER_VERY_AGGRESSIVE
-ec bit_mask 设置错误掩蔽为bit_mask,该值为如下值的位掩码 1 FF_EC_GUESS_MVS (default=enabled) 2 FF_EC_DEBLOCK (default=enabled)
-bf frames 使用frames B 帧,支持mpeg1,mpeg2,mpeg4
-mbd mode 宏块决策 0 FF_MB_DECISION_SIMPLE 使用mb_cmp 1 FF_MB_DECISION_BITS 2 FF_MB_DECISION_RD
-4mv 使用4个运动矢量 仅用于mpeg4
-part 使用数据划分 仅用于mpeg4
-bug param 绕过没有被自动监测到编码器的问题
-strict strictness 跟标准的严格性
-aic 使能高级帧内编码 h263+
-umv 使能无限运动矢量 h263+
-deinterlace 不采用交织方法
-interlace 强迫交织法编码仅对mpeg2和mpeg4有效。当你的输入是交织的并且你想要保持交织以最小图像损失的时候采用该选项。可选的方法是不交织,但是损失更大
-psnr 计算压缩帧的psnr
-vstats 输出视频编码统计到vstats_hhmmss.log
-vhook module 插入视频处理模块 module 包括了模块名和参数,用空格分开

4.音频选项

1
2
3
4
5
-ab bitrate 设置音频码率
-ar freq 设置音频采样率
-ac channels 设置通道 缺省为1
-an 不使能音频纪录
-acodec codec 使用codec编解码

5.音频/视频捕获选项

1
2
3
4
5
-vd device 设置视频捕获设备。比如/dev/video0
-vc channel 设置视频捕获通道 DV1394专用
-tvstd standard 设置电视标准 NTSC PAL(SECAM)
-dv1394 设置DV1394捕获
-av device 设置音频设备 比如/dev/dsp

6.高级选项

1
2
3
4
5
6
7
8
-map file:stream 设置输入流映射
-debug 打印特定调试信息
-benchmark 为基准测试加入时间
-hex 倾倒每一个输入包
-bitexact 仅使用位精确算法 用于编解码测试
-ps size 设置包大小,以bits为单位
-re 以本地帧频读数据,主要用于模拟捕获设备
-loop 循环输入流(只工作于图像流,用于ffserver测试)

15.压缩视频

1
ffmpeg -i target.mp4 -b:a 128k -b:v 7551k output.mp4

ffmpeg常用命令

一.基础概念

1.FFmpeg 的命令行参数非常多,可以分成五个部分。

1
ffmpeg {1} {2} -i {3} {4} {5}

上面命令中,五个部分的参数依次如下:

1
2
3
4
5
全局参数
输入文件参数
输入文件
输出文件参数
输出文件

2.参数太多的时候,为了便于查看,ffmpeg 命令可以写成多行。

1
2
3
4
5
6
ffmpeg \
[全局参数] \
[输入文件参数] \
-i [输入文件] \
[输出文件参数] \
[输出文件]

下面是一个例子。

1
2
3
4
5
6
ffmpeg \
-y \ # 全局参数
-c:a libfdk_aac -c:v libx264 \ # 输入文件参数
-i input.mp4 \ # 输入文件
-c:v libvpx-vp9 -c:a libvorbis \ # 输出文件参数
output.webm # 输出文件

3.FFmpeg 常用的命令行参数如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-c:指定编码器
-c copy:直接复制,不经过重新编码(这样比较快)
-c:v:指定视频编码器
-c:a:指定音频编码器
-i:指定输入文件
-an:去除音频流
-vn: 去除视频流
-preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
-y:不经过确认,输出时直接覆盖同名文件。

主要参数:
-i 设定输入流
-f 设定输出格式
-ss 开始时间
视频参数:
-b 设定视频流量,默认为200Kbit/s
-r 设定帧速率,默认为25
-s 设定画面的宽与高
-aspect 设定画面的比例
-vn 不处理视频
-vcodec 设定视频编解码器,未设定时则使用与输入流相同的编解码器
音频参数:
-ar 设定采样率
-ac 设定声音的Channel数
-acodec 设定声音编解码器,未设定时则使用与输入流相同的编解码器
-an 不处理音频

二.常用命令

1.视频画面上下翻转:

1
ffmpeg -i target.mp4 -vf vflip output.mp4

2.左右翻转:

1
ffmpeg -i target.mp4 -vf hflip output.mp4

3.画面顺时针旋转90度:

1
ffmpeg -i target.mp4 -vf transpose=1 output.mp4

4.画面逆时针旋转90°:

1
ffmpeg -i target.mp4 -vf transpose=2 output.mp4

5.查看文件信息

查看视频文件的元信息,比如编码格式和比特率,可以只使用-i参数。

1
ffprobe input.mp4

上面命令会输出很多冗余信息,加上-hide_banner参数,可以只显示元信息。

1
ffmpeg -i input.mp4 -hide_banner

6.转换编码格式

转换编码格式(transcoding)指的是, 将视频文件从一种编码转成另一种编码。比如转成 H.264 编码,一般使用编码器libx264,所以只需指定输出文件的视频编码器即可。

1
ffmpeg -i [input.file] -c:v libx264 output.mp4

下面是转成 H.265 编码的写法。

1
ffmpeg -i [input.file] -c:v libx265 output.mp4

7.转换容器格式

转换容器格式(transmuxing)指的是,将视频文件从一种容器转到另一种容器。下面是 mp4 转 webm 的写法。

1
ffmpeg -i input.mp4 -c copy output.webm

上面例子中,只是转一下容器,内部的编码格式不变,所以使用-c copy指定直接拷贝,不经过转码,这样比较快。

8.调整码率

调整码率(transrating)指的是,改变编码的比特率,一般用来将视频文件的体积变小。下面的例子指定码率最小为964K,最大为3856K,缓冲区大小为 2000K。

1
2
3
4
ffmpeg \
-i input.mp4 \
-minrate 964K -maxrate 3856K -bufsize 2000K \
output.mp4

9.改变分辨率(transsizing)

下面是改变视频分辨率(transsizing)的例子,从 1080p 转为 480p 。

1
2
3
4
ffmpeg \
-i input.mp4 \
-vf scale=480:-1 \
output.mp4

10.提取音频

有时,需要从视频里面提取音频(demuxing),可以像下面这样写。

1
2
3
4
ffmpeg \
-i input.mp4 \
-vn -c:a copy \
output.aac

上面例子中,-vn表示去掉视频,-c:a copy表示不改变音频编码,直接拷贝。

11.添加音轨

添加音轨(muxing)指的是,将外部音频加入视频,比如添加背景音乐或旁白。

1
2
3
ffmpeg \
-i input.aac -i input.mp4 \
output.mp4

上面例子中,有音频和视频两个输入文件,FFmpeg 会将它们合成为一个文件。

12.截图

下面的例子是从指定时间开始,连续对1秒钟的视频进行截图。

1
2
3
4
5
ffmpeg \
-y \
-i input.mp4 \
-ss 00:01:24 -t 00:00:01 \
output_%3d.jpg

如果只需要截一张图,可以指定只截取一帧。

1
2
3
4
5
ffmpeg \
-ss 01:23:45 \
-i input \
-vframes 1 -q:v 2 \
output.jpg

上面例子中,-vframes 1指定只截取一帧,-q:v 2表示输出的图片质量,一般是1到5之间(1 为质量最高)。

13.裁剪

裁剪(cutting)指的是,截取原始视频里面的一个片段,输出为一个新视频。可以指定开始时间(start)和持续时间(duration),也可以指定结束时间(end)。

1
2
ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]

下面是实际的例子。

1
2
ffmpeg -ss 00:01:50 -i [input] -t 10.5 -c copy [output]
ffmpeg -ss 2.5 -i [input] -to 10 -c copy [output]

上面例子中,-c copy表示不改变音频和视频的编码格式,直接拷贝,这样会快很多。

14.为音频添加封面

有些视频网站只允许上传视频文件。如果要上传音频文件,必须为音频添加封面,将其转为视频,然后上传。

下面命令可以将音频文件,转为带封面的视频文件。

1
2
3
4
5
ffmpeg \
-loop 1 \
-i cover.jpg -i input.mp3 \
-c:v libx264 -c:a aac -b:a 192k -shortest \
output.mp4

上面命令中,有两个输入文件,一个是封面图片cover.jpg,另一个是音频文件input.mp3。-loop 1参数表示图片无限循环,-shortest参数表示音频文件结束,输出视频就结束。

15.压缩视频

1
ffmpeg -i target.mp4 -b:a 128k -b:v 7551k output.mp4

Set接口

1.通用

(1)Set接口的特点
  • 不允许存储重复元素
  • 没有索引,没有带索引的方法,也不能使用普通for循环遍历

2.HashSet

(1)HashSet特点
  • 不允许存储重复的元素
  • 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
  • 是一个无序的集合,存储元素的取出元素的顺序有可能不一样
  • 底层是一个哈希表结构(查询的速度非常快)
(2)HashSet存储自定义类型元素
  • Set集合要保证元素唯一(String,Integer…Student,Person),必须重写hashCode方法和equals方法

3.哈希值

(1) 是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
(2)int hashCode() 返回该对象的哈希码值

4.Hash表(HashSet集合存储数据的结构)

(1)jdk8之前:
  • 哈希表=数组+链表
(2)jdk8之后:
  • 哈希表=数组+链表
  • 哈希表-数组+红黑树(提高查询的速度)
(3)哈希表的特点
  • 速度快

5.LinkedHashSet

(1)LinkedHashSet 继承自 HashSet
(2)LinkedHashSet集合特点:
  • 底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序
  • 并且不允许重复

6.可变参数

(1)可变参数:是JDK1.5之后出现的新特性
(2)使用前提:
  • 当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
(3)使用格式:定义方法时使用
1
修饰符 返回值类型 方法名(数据类型...变量名){}
(4)可变参数原理:
  • 可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,用来存储这些参数
  • 传递的参数个数,可以是0(不传递),1,2…多个
(5)示例
1
2
3
4
5
6
7
public static int sum(int...arr){
int sum = 0;
for(int i:arr){
sum+=i;
}
return sum;
}
(6)可变参数的注意事项
  • 一个方法的参数列表,只能有一个可变参数
  • 如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
1
2
3
4
5
6
7
public static int sum(String a,Double b,int...arr){
int sum = 0;
for(int i:arr){
sum+=i;
}
return sum;
}
(7)可变参数的特殊写法
1
2
3
public static void method(Object...obj){

}
  • Copyrights © 2015-2021 Movle
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信