java集合框架——工具类
一、概述
JAVA集合框架中有两个很重要的工具类,一个是Collections,另一个是Arrays。分别封装了对集合的操作方法和对数组的操作方法,这些操作方法使得程序员的开发更加高效。
public class Collections extends Object 全类名:java.util.Collections |
public class Arrays extends Object 全类名:java.util.Arrays |
二.Collections类
1.Collections.sort方法
public static <T extends Comparable<? super T>> void sort(List<T> list) |
public static <T> void sort(List<T> list, Comparator<? super T> c) |
(1)示例。
现在有一些字符串,可能有重复元素,想要将它们存入一个容器中并按照一定的规则进行排序,该怎么做?
思路:使用ArrayList集合进行存储并使用Collections.sort方法进行排序。
package p01.ColletionsDemo.p01.SortDemo; import java.util.ArrayList;
import java.util.Collections; public class SortDemo { public static void main(String[] args) {
Demo1(); }
private static void Demo1() {
ArrayList<String>al=new ArrayList<String>();
al.add("abc");
al.add("bca");
al.add("aab");
al.add("bac");
al.add("cba");
System.out.println("排序前:"+al);
Collections.sort(al);
System.out.println("排序后:"+al);
} }
这是按照字符串的自然排序方式排序的代码,即输出结果的字符串是按照字典序排序的。
现在有了新的需求,即按照字符串长度排序,如果字符串长度相同按照字典序排序,这时候需要使用比较器。
package p01.ColletionsDemo.p01.SortDemo; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; public class SortDemo {
public static void main(String[] args) {
//Demo1();
Demo2();
}
/*
* Demo2:该方法采用带比较器的Collections.sort方法
*/
private static void Demo2() {
ArrayList<String>al=new ArrayList<String>();
al.add("abcd");
al.add("abc");
al.add("bc");
al.add("aabadsf");
al.add("b");
al.add("cbae");
al.add("bade");
System.out.println("排序前:"+al);
Collections.sort(al,new ComparatorByLength());
System.out.println("排序后:"+al);
}
/*
* Demo1:该方法使用的是不带比较器的Collections.sort方法。
*/
private static void Demo1() {
ArrayList<String>al=new ArrayList<String>();
al.add("abc");
al.add("abc");
al.add("bca");
al.add("aab");
al.add("bac");
al.add("cba");
System.out.println("排序前:"+al);
Collections.sort(al);
System.out.println("排序后:"+al);
} }
class ComparatorByLength implements Comparator<String>
{ @Override
public int compare(String o1, String o2) {
int temp=o1.length()-o2.length();
return temp==0?o1.compareTo(o2):temp;
} }
两个重载方法使用起来非常方便,但是其实现原理是什么也需要了解。
(2)模拟不使用比较器的sort方法。
package p01.ColletionsDemo.p02.SortDemo; import java.util.ArrayList;
import java.util.List; class Person implements Comparable<Person>
{ private String name;
private int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
}
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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
@Override
public int compareTo(Person o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
class Student extends Person
{ public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} } public class SortDemo {
/**
* 该类模拟带不带比较器的Collections.sort方法。
* @param args
*/
public static void main(String[] args) { Demo1();
} private static void Demo1() {
ArrayList<Person>al=new ArrayList<Person>();
al.add(new Person("lisi",24));
al.add(new Person("wangwu",25));
al.add(new Person("zhangsan",23));
al.add(new Person("chenqi",27));
al.add(new Person("zhaoliu",26)); System.out.println("排序前:"+al);
MyCollections.sort(al);
System.out.println("排序后:"+al);
} }
/*
* 使用自定义Collections类
*/
class MyCollections
{
public static <T extends Comparable<? super T>> void sort(List <T>list)
{
for(int i=0;i<=list.size()-2;i++)
{
for(int j=i+1;j<=list.size()-1;j++)
{
if( list.get(i).compareTo(list.get(j))>0)
{
T t=list.get(i);
list.set(i, list.get(j));
list.set(j, t);
}
}
}
}
}
(3)模拟使用比较器的sort方法。
package p01.ColletionsDemo.p03.SortDemo; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator; class Person implements Comparable<Person>
{ private String name;
private int age;
@Override
public String toString() {
return "name="+name + ", age=" + age +"\n";
}
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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
@Override
public int compareTo(Person o) {
int temp=this.age-o.getAge();
return temp==0?this.name.compareTo(o.getName()):temp;
}
}
class Student extends Person
{ @Override
public String toString() {
return super.toString() ;
} public Student() {
super();
} public Student(String name, int age) {
super(name, age);
} }
class Worker extends Person
{ @Override
public String toString() {
return super.toString();
} public Worker() {
super();
} public Worker(String name, int age) {
super(name, age);
} } public class SortDemo {
/**
* 该类模拟带不带比较器的Collections.sort方法。
* @param args
*/
public static void main(String[] args) { // Demo1();
// Demo2();
Demo3();
} private static void Demo3() {
ArrayList<Student>al=new ArrayList<Student>();
al.add(new Student("lisi",24));
al.add(new Student("wangwu",25));
al.add(new Student("zhangsan",23));
al.add(new Student("chenqi",27));
al.add(new Student("zhaoliu",26)); System.out.println("排序前:"+al);
MyCollections_1.sort(al,new ComparatorByLength());
//Collections.sort(al, new ComparatorByLength());
System.out.println("排序后:"+al);
} private static void Demo1()
{
ArrayList<Person>al=new ArrayList<Person>();
al.add(new Student("lisi",24));
al.add(new Person("wangwu",25));
al.add(new Worker("zhangsan",23));
al.add(new Person("chenqi",27));
al.add(new Person("zhaoliu",26)); System.out.println("排序前:"+al); System.out.println("排序后:"+al);
} }
class MyCollections_1
{
public static <T> void sort(List <T>list,Comparator<? super T> c)
{
Object [] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++)
{
i.next();
i.set(a[j]);
}
}
}
class ComparatorByLength implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().length()-o2.getName().length();
return temp==0?o1.getName().compareTo(o2.getName()):temp;
}
}
其实,Collectios.sort方法的实质就是将集合转换成数组,然后使用Arrays工具类的sort方法进行排序,最后根据排序结果修改原集合
2.Collections.binarySearch方法
public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key) |
public static <T> int binarySearch(List<? extends T> list,T key,Comparator<? super T> c) |
这两个方法中,前者是不带比较器的二分查找方法,后者是带着比较器的二分查找方法。
既然是二分查找法,那么集合中的元素必然是有序的;如果元素不带有比自然比较的属性,则必须使用比较器,否则元素必须具备自然比较的属性,即实现了Comparable接口。
(1)简单的使用方法(不带比较器)演示
package p02.ColletionsDemo.p01.BinarySearchDemo; import java.util.ArrayList;
import java.util.Collections; public class BinarySearchDemo { public static void main(String[] args) {
Demo01();
Demo02();
}
/**
* 没经过排序的集合使用二分查找法
*/
private static void Demo02() {
ArrayList<String>al=new ArrayList<String>();
al.add("abc");
al.add("dabdc");
al.add("cd");
al.add("bac");
al.add("ba");
System.out.println(al);
int index=Collections.binarySearch(al, "ba");
System.out.println(index);
}
/**
* 经过排序的集合使用二分查找法
*/
private static void Demo01() {
ArrayList<String>al=new ArrayList<String>();
al.add("abc");
al.add("dabdc");
al.add("cd");
al.add("bac");
al.add("ba");
Collections.sort(al);
System.out.println(al);
int index=Collections.binarySearch(al, "ba");
System.out.println(index);
} }
如果没有找到关键字,则会返回一个负数,该负数是如果将该数插入集合应当插入的位置*-1-1。减一的目的是为了防止应当插入的位置是0。
(2)复杂的使用方法演示(存放自定义对象,并使用了自定义比较器)
package p02.ColletionsDemo.p02.BinarySearchDemo; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; class Person implements Comparable<Person>
{
public String name;
public int age; @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]\n";
} public Person(String name, int age) {
super();
this.name = name;
this.age = age;
} public Person() {
super();
} @Override
public int compareTo(Person o) {
int temp=this.age-o.age;
return temp==0?this.name.compareTo(o.name):temp;
}
}
public class BinarySearchDemo {
public static void main(String[] args) {
Demo01(); /*
* 按照名字的字典序排序,并查找,如果名字相同,则按照年龄排序
*/
Demo02();
} /*
* 使用带比较器的二分查找方法
*/
private static void Demo02() {
ArrayList<Person>al=new ArrayList<Person>();
al.add(new Person("zhaoliu",26));
al.add(new Person("lisi",24));
al.add(new Person("zhangsan",23));
al.add(new Person("wangwu",25));
al.add(new Person("wangwu",23));
al.add(new Person("wangwu",22));
al.add(new Person("wangwu",21));
Collections.sort(al,new ComparatorByName());
System.out.println(al);
int index=Collections.binarySearch(al,new Person("wangwu",25),new ComparatorByName());
System.out.println(index);
} /*
* 不使用带比较器的二分查找方法。
*/
private static void Demo01() {
ArrayList<Person>al=new ArrayList<Person>();
al.add(new Person("zhaoliu",26));
al.add(new Person("lisi",24));
al.add(new Person("zhangsan",23));
al.add(new Person("wangwu",25));
al.add(new Person("wangwu",23));
al.add(new Person("wangwu",22));
al.add(new Person("wangwu",21));
Collections.sort(al);
System.out.println(al);
int index=Collections.binarySearch(al,new Person("wangwu",25));
System.out.println(index);
} }
class ComparatorByName implements Comparator<Person>
{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.name.compareTo(o2.name);
return temp==0?o1.age-o2.age:temp;
} }
3.最大值最小值方法
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) |
public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp) |
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) |
public static <T> T min(Collection<? extends T> coll,Comparator<? super T> comp) |
package p03.ColletionsDemo.p01.MaxMainDemo; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; public class MaxMinDemo { public static void main(String[] args) {
Demo01(); } private static void Demo01() {
ArrayList<String>al=new ArrayList<String>();
al.add("bcade");
al.add("abc");
al.add("baefgh");
al.add("b");
/*
* 按照默认比较方式进行比较
*/
String max=Collections.max(al);
String min=Collections.min(al);
System.out.println("max="+max);
System.out.println("min="+min); System.out.println();
/*
* 更改比较方式,按照长度进行比较
*/
ComparatorByStringLength cbsl=new ComparatorByStringLength();
String max_1=Collections.max(al,cbsl);
String min_1=Collections.min(al,cbsl);
System.out.println("max="+max_1);
System.out.println("min="+min_1);
} }
/*
* 按照长度进行比较
*/
class ComparatorByStringLength implements Comparator<String>
{
@Override
public int compare(String o1, String o2) {
int temp=o1.length()-o2.length();
return temp==0?o1.compareTo(o2):temp;
}
}
4.反转和逆序
public static void reverse(List<?> list) |
public static <T> Comparator<T> reverseOrder() |
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) |
package p04.ColletionsDemo.p01.ReverseOrderDemo; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; public class ReverseOrderDemo { public static void main(String[] args) {
//直接得到逆序的比较器从而将结果逆序。
Demo01();
//将比较器逆序从而将结果逆序。
Demo02();
} /*
* 按照长度进行排序(自定义比较器)并逆序
*/
private static void Demo02() {
ArrayList<String>al=new ArrayList<String>();
al.add("defefe");
al.add("edfef");
al.add("abce");
al.add("ba");
al.add("ab");
ComparatorByStringLength cbsl=new ComparatorByStringLength();
Collections.sort(al,cbsl);
System.out.println(al);
Collections.sort(al,Collections.reverseOrder(cbsl));//实现比较器的逆序。
System.out.println(al);
} private static void Demo01() {
ArrayList<String>al=new ArrayList<String>();
al.add("defefe");
al.add("edfef");
al.add("abce");
al.add("ba");
al.add("ab");
Collections.sort(al);
System.out.println(al);
Collections.sort(al,Collections.reverseOrder());//实现逆序
System.out.println(al);
}
}
/*
* 按照长度进行比较
*/
class ComparatorByStringLength implements Comparator<String>
{
@Override
public int compare(String o1, String o2) {
int temp=o1.length()-o2.length();
return temp==0?o1.compareTo(o2):temp;
}
}
5.替换
public static <T> boolean replaceAll(List<T> list,T oldVal,T newVal) |
使用这个方法的时候如果List中存放的是自定义对象,则应当复写equals方法。
package p05.ColletionsDemo.p01.ReplaceAllDemo; import java.util.ArrayList;
import java.util.Collections; class Person
{
public String name;
public int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
@Override
public String toString() {
return "name=" + name + ", age=" + age + "\n";
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
* 如果想要使用Collections.repalceAll方法,则必须复写自定义对象的equals方法。
*/
@Override
public boolean equals(Object obj) {
Person p=(Person)obj;
return this.age==p.age&&this.name==p.name?true:false;
}
} public class ReplaceAllDemo { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
ArrayList<Person>al=new ArrayList<Person>();
al.add(new Person("zhangsan",23));
al.add(new Person("lisi",24));
al.add(new Person("wangwu",25));
al.add(new Person("zhaoliu",26)); System.out.println(al);
Collections.replaceAll(al, new Person("zhangsan",23),new Person("chenqi",27));
System.out.println(al);
} }
6.最重要的问题:同步集合的问题
Colletions类中提供了几种方法可以将非同步的集合转变成同步集合,这是为了满足在多线程环境下编程的需求。
public static <T> Collection<T> synchronizedCollection(Collection<T> c) |
public static <T> List<T> synchronizedList(List<T> list) |
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) |
public static <T> Set<T> synchronizedSet(Set<T> s) |
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) |
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) |
下面的代码实现了自定义同步集合以及使用上述方法生成的同步集合,两种方法相比较,很明显,使用工具类能够大大提高效率。注意自定义集合中泛型的使用。
package p07.ColletionsDemo.p01.SynchronizedFunctionDemo; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List; public class SynchronizedFunctionDemo { public static void main(String[] args) {
Demo01();//自定义同步集合 Demo02();//使用Collecionts.xxx得到同步的集合
} private static void Demo02() {
/*
* 使用Collections提供的方法则要简单的多。
*/
List<String>list=Collections.synchronizedList(new ArrayList<String>());
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.remove("lisi");
Iterator<String>it=list.iterator();
while(it.hasNext())
{
String str=it.next();
System.out.println(str);
}
} private static void Demo01() {
MyList <String>list=new MyList<String>(new ArrayList<String>());
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.remove("lisi");
Iterator<String>it=list.iterator();
while(it.hasNext())
{
String str=it.next();
System.out.println(str);
}
}
} /*
* 该类将List集合转换成同步的List集合,需要重新写许多方法,非常麻烦
*/
class MyList<E>
{
private List<E> list;
private final Object obj=new Object();
public MyList(){}
public MyList(List<E> list)
{
this.list=list;
}
public boolean add(E obj)
{
synchronized(obj)
{
return this.list.add(obj);
}
}
public boolean remove(E obj)
{
synchronized(obj)
{
return this.list.remove(obj);
}
}
public Iterator<E> iterator()
{
/*
* 没有涉及到元素的删除和添加就不加同步。
*/
return this.list.iterator();
}
}
7.其它方法
public static <T> Enumeration<T> enumeration(Collection<T> c) |
public static <T> ArrayList<T> list(Enumeration<T> e) |
public static <T> void fill(List<? super T> list,T obj) |
public static void shuffle(List<?> list) |
public static void shuffle(List<?> list,Random rnd) |
三、Arrays类
1.toString方法
public static String toString(int[] a) |
上述的方法只是一个例子,该方法由多种重载形式。可以接受的参数包括各种基本数据类型。
功能是返回指定数组内容的字符串表示形式。
package p08.ArraysDemo.p01.ToStringDemo; import java.util.Arrays; public class ToStringDemo { public static void main(String[] args) {
Demo01();
}
private static void Demo01() {
int[]arr=new int[10];
for(int i=0;i<arr.length;i++)
{
arr[i]=i;
}
String str=Arrays.toString(arr);
System.out.println(str);
} }
2.asList方法
public static <T> List<T> asList(T... a) |
该方法使用了可变参数,这点应当注意。功能是返回一个受指定数组支持的固定大小的列表,也就是将数组转换成集合的方法。该方法的目的是使用更多的方法对数组的元素进行操作,毕竟数组中的方法并不多,即使有了Arrays方法也还是不够,如果能转换成集合进行操作,将能够使用更多更有效的方法,比如contains方法等。
package p09.ArraysDemo.p01.AListDemo; import java.util.Arrays;
import java.util.List; public class AlistDemo { public static void main(String[] args) {
Demo01();
Demo02();
} /**
* 如果数组存放基本数据类型,则转变成集合之后存放的是数组的引用
*/
private static void Demo02() {
int arr[]=new int[10];
for(int i=0;i<arr.length;i++)
{
arr[i]=i;
}
List<int[]>list_1=Arrays.asList(arr);
System.out.println(list_1); Integer arr_1[]=new Integer[10];
for(int i=0;i<arr.length;i++)
{
arr_1[i]=i;
}
List<Integer>list_2=Arrays.asList(arr_1);
System.out.println(list_2);
} /**
* 如果数组内存放对象,则存放的是一个个对象的内容
*/
private static void Demo01() {
String arr[]=new String[10];
for(int i=0;i<arr.length;i++)
{
arr[i]=i+"";
}
List<String>list=Arrays.asList(arr);
System.out.println(list);
} }
注意,虽然该方法可以将数组转换成集合,但是不能进行增删操作,否则会有异常产生,这是因为数组就是数组的长度是不可变的。
3.集合转数组的方法:toArray
集合转换成数组的目的一般就是减小对元素的操作权限,比如不允许增删操作了。
package p10.ArraysDemo.p01.ListToArr; import java.util.ArrayList; public class ListToArr { public static void main(String[] args) {
Demo01();
} private static void Demo01() {
ArrayList <Integer>list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list);
Integer []arr=list.toArray(new Integer[list.size()]);//将集合转变成数组,注意类型应当匹配,否则会抛出ArrayStoreException异常。
System.out.println(arr);
for(int i=0;i<arr.length;i++)
{
System.out.println(arr[i]);
}
} }
java集合框架——工具类的更多相关文章
- Java 集合框架工具类
Collections Arrays Collections 集合框架的工具类, 里面的方法都是静态的, 可以直接使用类名调用 常用方法 1. sort(List<T> list); // ...
- java集合框架工具类Collections,集合的操作
1 import java.util.*; public class asList { public static void main(String args[]) { // int arr[] = ...
- JAVA基础学习之 Map集合、集合框架工具类Collections,Arrays、可变参数、List和Set集合框架什么时候使用等(4)
package com.itcast.test20140113; import java.util.ArrayList; import java.util.Arrays; import java.ut ...
- java基础37 集合框架工具类Collections和数组操作工具类Arrays
一.集合框架工具类:Collections 1.1.Collections类的特点 该工具类中所有的方法都是静态的 1.2.Collections类的常用方法 binarySearch(List< ...
- Java集合——Collections工具类
Java集合——Collections工具类 摘要:本文主要学习了Collections工具类的常用方法. 概述 Collections工具类主要用来操作集合类,比如List和Set. 常用操作 排序 ...
- java 集合Collections 工具类:排序,查找替换。Set、List、Map 的of方法创建不可变集合
Collections 工具类 Java 提供1个操作 Set List Map 等集合的工具类 Collections ,该工具类里提供了大量方法对集合元素进行排序.查询和修改等操作,还提供了将集合 ...
- Java集合----Collection工具类
Collections 工具类 Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询和修改等操作,还提供了 ...
- Java基础---泛型、集合框架工具类:collections和Arrays
第一讲 泛型(Generic) 一.概述 1.JDK1.5版本以后出现的新特性.用于解决安全问题,是一个类型安全机制. 2.JDK1.5的集合类希望在定义集合时,明确表明你要向集合中装入那种类 ...
- 集合框架-工具类-Arrays-asList方法
1 package cn.itcast.p3.toolclass.arrays.demo; 2 3 import java.util.ArrayList; 4 import java.util.Arr ...
随机推荐
- P1029 最大公约数和最小公倍数问题(思维题)
题目描述 输入22个正整数x_0,y_0(2 \le x_0<100000,2 \le y_0<=1000000)x0,y0(2≤x0<100000,2≤y0<=100 ...
- 华东交通大学2015年ACM“双基”程序设计竞赛1005
Problem E Time Limit : 3000/2000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Sub ...
- Codeforces Round #339 (Div. 2) A
Description Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, which ...
- python—datetime time 模板学习
写在前面:本人在学习此内容是通过 https://www.cnblogs.com/pycode/p/date.html 文章学习! 时间模块——time python 中时间表示方法有:时间戳_:格式 ...
- Unity GetComponents获取组件
Component[] componments2 = gameObject.GetComponents<Component>(); Debug.Log("componments2 ...
- PlayMaker Action的执行顺序
如图:默认的是从上到下 先执行Play Sound,再执行Destroy Object. 可以点击右上角的齿轮,也就是设置按钮选中Action Sequence,这样就会同时执行.
- 性能测试工具LoadRunner12-LR之Virtual User Generator 脚本编写验证步骤以及LR常见错误处理方法
验证脚本比较好的流程: Generate:录制或开发脚本 SUSI(Single User Single Iteration,单用户单循环):运行录制生成的脚本,解决可能存在的关键问题 SUMI(Si ...
- SecureCRT中文乱码解决方案
SecureCRT是一个商业终端连接工具.SecureCRT可以自定义界面颜色方案,可以连接SSH1与SSH2.Telnet等服务.默认设置下,通过SecureCRT连接SSH服务器可能出现中文乱码的 ...
- 浅入分析Linux
Linux 操作系统必须完成的两个主要目的 与硬件部分交互, 为包含在硬件平台上的所有底层可编程部件提供服务 为运行在计算机系统上的应用程序(即所谓的用户空间)提供执行环境 一些操作系统运行所有的用户 ...
- FileZila
FileZilla下载文件失败的原因 对应访问的目录在服务器上没有权限下载 在本地没有切换到用户的家目录