Java总结

2 面向对象基础

三大特征:

一 封装:

概念:是指隐藏对象的属性和实现细节,仅对外提供访问的方式

好处:将变化隔离;便于使用;提高重用性;安全性。

单例设计模式:

解决的问题:保证一个类在内存中的对象唯一性。

Runtime()方法就是单例设计模式进行设计的。

如何保证对象的唯一性呢?

思想:

1,不让其它程序创建该对象。

2,在本类中创建一个本类对象。

3,对外提供方法,让其他程序获取这个对象。

//饿汉式
class Single
{
	private Single(){}//私有化构造函数
	private Static Single s = new Single();//创建私有并静态的本类对象。
	public Static Single getInstance(){return s}//定义共有并静态的方法,返回该类对象
}
------------------------------
//懒汉式
class Single2
{
	private Single2(){}
	private static Single2 s=null;
	public static Single2 getInstance()
	{
		if(s==null)
			s = new Single2();
		return s;
	}
}
二 继承

好处:

1:提高了代码的复用性。

2:让类与类之间产生了关系。

final特点

1:这个关键字是一个修饰符,可以修饰类,方法,变量。

2:被final修饰的类是一个最终类,不可以被继承。

3:被final修饰的方法是一个最终方法,不可以被覆盖。

4:被final修饰的变量是一个常量,只能赋值一次。

抽象类的特点:

1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰。

2:抽象方法只定义方法的声明,并不定义方法的实现。

3:抽象类不可以被创建对象。

4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

5:抽象只能单继承。

接口:

抽象类和接口的区别:

1:抽象类只能被继承,而且只能单继承。

       接口需要被实现,而且可以多实现。

2:抽象类中可以定于非抽象方法,子类可以直接继承使用。

      接口中都有抽象方法,需要子类去实现。

3:抽象类使用的是 is a关系

      接口使用的是like a关系

4:抽象类的成员修饰可以自定义。

      接口中的成员修饰符是固定的。全是public的

三  多态

多态:函数本身就具备多态性,某一种事物有不同的具体的体现。

体现:父类引用或者接口的引用指向了自己的子类对象。//Animal a = new Cat();

多态好处:提高了程序的扩展性。

多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。访问的局限性。

匿名内部类:没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式

匿名内部类的格式:new 父类名&接口名(){定义子类成员或者覆盖父类方法}.方法。

异常:

异常处理原则:功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码块,这样处理有针对性,抛几个处理几个。

特殊情况:try对应多个catch时,如果有父类的catch语句块,一定要放在最下面。

throw 和 throws关键字的区别:

throw用于抛出异常对象,后面跟是异常对象;throw用在函数内。

throws用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws用在函数上。

2 多线程

线程的2种创建方式

创建线程的第一种方式:继承Thread,由子类覆写run方法。

class  Th1
{
	public static void main(String[] args) 
	{
		Thread1 th = new Thread1();
		th.start();
	}
}
class Thread1 extends Thread
{
	public void run()
	{
		//线程执行的内容
	}
}
 线程状态:

新建:start()

运行:具备执行资格,同时具备执行权。

冻结:sleep(time),wait()--notify()唤醒;线程释放了执行权,同时释放执行资格。

临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权。

消亡:Stop()

创建多线程第二种方式:实现一个接口 Runnable。

class Th2 
{
	public static void main(String[] args) 
	{
		Thread2 t = new Thread2();
		Thread th = new Thread(t);
		th.start();
	}
}
public Thread2 implements Runnable
{
	public void run()
	{
		//线程执行内容
	}
}
多线程安全问题的原因:
一个线程在执行多条语句时,并运算同一个数据时,在执行过程中,其它线程参与进来,并操作了这个数据。导致错误数据的产生。

解决安全问题的原理:

只要将操作的共享数据的语句在某一时段让一个线程执行完,在执行过程中,其他线程不能进来执行就可以解决这个问题。

java中提供了一个解决方案方式:就是同步代码块。

格式:

Synchronized(对象){//对任意对象都可以,这个对象就是锁

需要被同步的代码;

}

wait 和sleep区别:

wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者 notigyAll来唤醒。

sleep:必须指定时间,时间到自动从冻结状态转成运行状态。

wait:线程会释放执行权,而且线程会释放锁。

Sleep:线程会释放执行权,但不会释放锁。

同步嵌套同步代码块会产生死锁。

4 集合框架

常用的ArrayList  HashSet


Collection:

|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。

|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList代替了Vector 。查询速度很快。

|--LinkedList:底层的数据结构是链表,线程不同步,增删很快。

|--Vector:底层的数据结构是数组,线程同步,查询增删都很慢。

1,添加:

add(index,element)

bool addAll(index,collection)

2,删除

E remove(index)

3,获取

int get(index)

int indexOf(obj)

int lastIndexOf(obj)

List<E> subList(start,end)

4,修改:

E set(index,element)

5,获取所有元素

ListIterator listIterator():list集合特有的迭代器。(具备了对元素的增、删、改、查)

List集合因为角标有了自己的获取元素的方式:遍历。

for(int x=0;x<list.size();x++){

System.out.println("get:"+list.get(x));

}

|--Set:无序,不可以存储重复元素。必须保证元素的唯一性。

1,添加

add(object)

addAll(Collection)

2,删除

clear()

remove(obj)

removeAll(collection)

3,判断

boolean contains(obj)

boolean containsAll(collection)

boolean isEmpty()

4,获取:

int size()

5,取交集:

boolean retainAll(collection)//仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。

6,获取集合中所有元素:

Iterator iterator()

7,将集合变成数组:

toArray();

|--HashSet:底层数据结构是哈希表,线程不同步,无序,高效。

HashSet集合保证元素唯一性:通过元素的hashCode方法,和equals方法完成的,当元素的hashCode值相同时,才继续判断元素equals是否为true。如果为true,那么视为相同元素,不存。如果为false,那么存储。在原来对象的哈希值基础+1顺延。

|--LinkedHashSet:有序,HashSet的子类。

|--TreeSet:对Set集合中的元素的惊醒指定顺序的排序。不同步。TreeSet底层的结构是二叉树。

哈希表原理:

1,对对象元素中的关键字(对象中特有的数据),进行哈希算法运算,并得出一个算法值,这个值称为哈希值。

2,哈希值就是这个元素的位置。

3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同 ,不存储,因为元素重复,如果相同,就存储,在原来对象的哈希值基础+1顺延。

4,存储哈希值的结构,我们称为哈希表。

5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象关键字是唯一,这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。

TreeSet:

对于Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。如果元素不具备比较性,在运行时会发生ClassCastException异常。

所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。

TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。

注意:在进行比较时,如果判断元素不唯一,比如哦,同姓名,同年龄,才视为同一个人。在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。

TreeSet集合排序有两种方式,Comparable和Comparator区别:

1:让元素自身具备可比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。

2:让集合自身具备可比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。

------------------------------------------------------------------------------------------------------------------------------------------------

Map集合:

|--Hashtable:底层是哈希表数据结构,是线程同步。不可以存储null键 null值

|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键 null值,代替了Hashtable.

|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定的顺序的排序。

Map集合存储和Collection有着很大的不同:

Collection一次存一个元素;Map一次存一对元素。

Collection是单列集合;Map 是双列集合。

Map中的存储的一对元素:一个键,一个是值,键与值之间有对应关系

特点:要保证map集合中键的唯一性。

1,添加。

put(key,value)

putAll(Map)

2,删除。

clear()

value remove(key);

3,判断

boolean isEmpty()

boolean containsKey(key)

boolean contansValue(value)

4,取出。

int size()

value get(key)

Collection values();

5,想要获取map中所有元素:

原理:map中没有迭代器的,collection具备迭代器,只要将map集合转成Set集合,可以使用迭代器了。之所以转成set,是因为map集合具备这键的唯一性,其实set来自map,set集合底层其实用的就是map方法。

把map集合转成set的方法:

Set keySet();

Set entrySet();

Entry就是Map接口中的内部接口;

为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口中的键值对。

----------------------------------------------------------------------------------------------------------

取出map集合中所有元素的方式一:keySet()方法。

Set  keySet = map.keySet();

Iterator it = keySet.iterator();

while(it.hasNext()){

Object key = it.next();

Object value = map.get(key);

System.out.println(key+":"+vlalue);

}

------------------------------------------------------------------------------------------------------------

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();

Iterator it = entrySet.iterator();

while(it.hasNext()){

Map.Entry me = (Map.Entry)it.next();

System.out.println(me.getKey()+":"+me.getValue());

}

----------------------------------------------------------------------------------------------

使用集合的技巧

看到Array就是数组结构,有角标,查询速度很快。

看到link就是链标结构,增删速度快,而且有特有的方法。addFirst();addLast();removeFirst();removeLast();getFirst();getLast();

看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该集合元素必须覆盖hashCode,equals方法。

看到tree就是二叉树,就要想到排序,就想要用到比较。

比较的两种方式:

一个是Comparable:覆盖compareTo方法;

一个是Comparator:覆盖compare方法。

LinkedHashSet,LinkedHashMap:这两个集合可以保存哈希表存入顺序和取出顺序一致,保证哈希表有序。

集合什么时候用?

当存储的是一个元素时,就用Collection。当存储对象之间存在映射关系时,就使用Map集合。保证唯一,就用Set,不保证唯一,就用List。

-----------------------------------------------------------------------------------------------------------

Coollections:它的出现给集合操作提供了更多的功能。这个类提供的都是静态方法。

静态方法:

Collections.sort(list);

Collections.sort(list,new ComparatorByLen());//指定比较器方法

class ComparatorByLen implements Comparator<String>{

jpublic int compare(String s1,String s2){

inte temp0 = s1.length()-s2.length();

return tem==0?s1.compareTo(s2):temp;

}

}

Collections.max(list)

int index = Collections.binarySearch(list,"zz");//二分查找,放回角标。

Collection.reverseOrder();

Collection.shuffle(list);

将非同步集合转成同步集合的方法:Collections中的  XXX synchronizedXXX(XXX);

List synchronizedList(list);

Map synchronizedMap(map);

原理:定义一个类,将集合所有的方法加同一把锁后返回。

Collection和Collections的区别:

Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找,排序,替换,线程安全化 等。

Collection是个java.util下的接口,他是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否是其成员、遍历等。

------------------------------------------------------------------------------------------------------

Arrays:

用于操作数组对象的工具类,里面都是静态方法。

asList(arr):将数组转换成list集合。

String[] arr = {"aa","bbb"};

List<String> list = Arrays.asList(arr);

将数组转换成集合,有什么好处呢?

可以通过list集合中的方法来操作数组中的元素:isEmpty()、contains、indexof、set;;

主要(局限性):数组是固定长度,不可以使用集合对象增加或者删除等,会改变数组长度的功能方法。比如add、remove、clear

集合变数组:用的Collection接口中的方法:toArray();

将集合变成数组后又什么好处?限定了对集合中的元素进行增删操作,只要获取这些元素即可。

---------------------------------------------------------------------------------

Java 1.50新特性

Jdk1.50新特性:

Collection在jdk1.5后,有了一个父接口Iterable,这个接口的出现将iterator方法进行抽取,提高了扩展性。

---------------------------------------------------------------------------------------

增强for循环

fro(元素类型  变量名 :Collection 集合 & 数组){

..................

}

-------------------------------------------------------------

可变参数(...):

用到函数的参数上,当药操作一个类型元素个数不确定的时候,可是用这个方式,这个参数可以接受任意个数的同一个类型的数据。

public class VarArgsTest {

    public void print(String... args) {
        for (int i = 0; i < args.length; i++) {
            out.println(args[i]);
        }
    }

    public void print(String test) {
        out.println("----------");
    }

    public static void main(String[] args) {
        VarArgsTest test = new VarArgsTest();
        test.print("hello");
        test.print("hello", "alexia");
    }
}

------------

hello

alexia

------------------------------------------------------

枚举:关键字enum

问题:对象的某个属性的值不能是任意的,必须为固定的一组取值其中的某一个;

jdk1.5中新定义了枚举类型,专门用于解决此类问题;

枚举就是一个特殊的java类,可以定于属性、方法、构造函数、实现接口、继承类;

---------------------------------------------------------------------------

自动拆装箱:java中数据类型分为两种:基本数据类型  引用数据类型(对象)

在java程序中所有的数据都需要当作对象来处理,针对8种基本数据类型提供了包装类,如下:

int-->Integer

byte-->Byte

short-->Short

long-->Long

char-->Character

double-->Double

float-->Float

boolean-->Boolean

基本数据类型和包装类型之间需要互转:

基本---引用  Integer x= new Integer(x)

引用---基本  int  num = x.intValue();

1,Integer x= 1; x=x+1;经历了什么过程?装箱->拆箱->装箱;

2,为了优化,虚拟机为包装类提供了缓冲池,Integer池的大小-128~127 一个字节的大小;

3,String池:java为了优化字符串操作  提供了一个缓冲池;

---------------------------------------------------------------------------------

泛型:jdk1.5版本后出现的一个安全机制。表现格式:<>

好处:

1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。

2:避免了强制转换的麻烦。

只要带有<>的类或者接口,都属于带有类型参数的类或者接口,在使用这些类或者接口时,必须给<>中传递一个具体的引用数据类型。

泛型技术:其实应用在编译时期,是给编译器使用的技术,到了运行时期,泛型就不存在了。为什么?因为泛型的擦除:也就是说,编辑器检查了泛型的类型正确后,在生成的类文件中是没有泛型的。

在运行时,如何知道获取的元素类型而不用强转呢?

泛型的补偿:因为存储的时候,类型已经确定了是同一个类型的元素,所以在运行时,只要获取到该元素的类型,在内部进行一次转换即可,所以使用者不用再做转换动作了。

什么时候用泛型呢?

当类中的操作的引用数据类型不确定的时候,以前用的Object来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到编译时期。

----------------------------------------

泛型程序中的体现:

//泛型类:将泛型定义在类上。
class Tool<Q>
{
	private Q obj;
	public void setObject(Q obj)
	{
		this.obj = obj;
	}
	public Q getObject(){
		return obj;
	}
}
//当方法操作的引用数据类型不确定的时候,可以将泛型定义在方法上。
public <W> void method(W w){
	System.out.println("method:"+w);
}
//静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
public static <Q> void function(Q t){
	System.out.println("function:"+t);
}
//泛型接口
interface Inter<T>
{
	void show(T t);
}
class InterImpl<R> implements Inter<R>
{
	public void show(R r)
	{
		System.out.println("show:"+r);
	}
}
--------------------------------------------------------------------------

泛型中的通配符:可以解决当具体类型不确定的时候,这个通配符就是?;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用?通配符来表示未知类型。

泛型限定:

上限: ? extends E :可以接收E类型或者E的子类类型对象。

下限: ?super E:可以接收E类型或者E类型的父类类型对象。

上限什么时候用:往集合中添加元素时,既可以添加E类型对象,又可以添加E的子类类型对象。为什么?因为取的时候,E类型即可以接收E类对象,又可以接收E的子类型对象。

下限什么时候用:当从集合中获取元素进行操作的时候,可以用当前元素的类型接收,也可以用当前元素的父类型接收。

泛型的细节:

1、泛型到底代表什么类型取决于调用者传入的类型,如果没传,默认是Object类型;

2、使用带泛型的 类创建对象时,等式两边指定的泛型必须一致;

原因:编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了;

3、等式两边可以在任意一边使用泛型,在另一边不使用(考虑向后兼容);

ArrayList<String> al = new ArrayList<Object>();//错

//要保证左右两边的泛型具体类型一致就可以了,这样不容易出错。

ArrayList<? extends Object> al = new ArrayList<String>();

al.add("aa");//错

//因为集合具体对象中即可存储String,也可以存储Object的其他子类,所以添加具体的类型对象不合适,类型检查安全出现安全问题。 ? extends Object 代表Object的子类类型不确定,怎么能添加具体的对象呢?

public static void method(ArrayList<? extends Object> al){

al.add("abc");//错

}

//只能对al集合中的元素调用Object类中的方法,具体子类类型方法都不能用,因为子类类型不确定。

5 IO流


-----------------------------------------------------------------------------------------------------------------------------------

字符流:

Reader:用于读取字符流的抽象类。子类必须实现的方法只有read(char[],int,int)和close().

|--BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认的大小。

|--LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法setLineNumber(int)和getLineNumber(),他们可分别用于设置和获取当前行号。

|--InputStreamReader:是字节流通向字符流的桥梁:他使用指定的charset读取字节并将其解码为字符。它使用字符集可以由名称指定或显示给定。

|--FileReader:用来读取字符文件的便捷类。此类的构造方法默认字符编码。

|--CharArrayReader:

|--StringReader:

-----------------------------------------------------------

Writer:写入字符流的抽象类。子类必须实现的方法有write(char[],int,int)、flush()和close()。

|--BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

|--OutputStreamWriter:是字符流通向字节流的桥梁:可以使用指定的charset将写入流中的字符编码成字节。它使用的字符集可以由名称指定或显示给定。

|--Filewriter:用来写入字符文件的便捷类。此类的构造方法默认字符编码。

|--PrintWriter:

|--CharArrayWriter:

|--StringWriter:

-------------------------------------------------------------------

字节流:

InputStream:是标识字节输入流的所有类的超类。

|--FileInputStream:从文件系统中的某个文件中获得输入字节。FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用FileReader。

|--FilterInputStream:包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。

|--BufferedInputStream:该类实现缓冲的输入流

|--Stream:

|--ObjectInputStream:

|--PipedInputStream:

-----------------------------------------------

OutputStream:此抽象类是表示输出字节流的所有类的超类。

|--FileOutputStream:文件输出流是用于将数据写入File或FileDescriptor的输入流。

|--FilterOutputStream:此类是过滤输出流的所有类的超类。

|--BufferedOutputStream:该类实现缓冲的输出流。

|--PrintStream:

|--DataOutputStream:

|--ObjectOutputStream:

|--PipedOutputStream:

--------------------------------------------------

缓冲区是提高效率用的,给谁提高呢?

BufferedWriter:是给字符输出流提高效率用的,那就意味着,缓冲区对象创建时,必须要先有流对象。明确要提高具体的流对象的效率。

FileWriter fw = new FileWriter("bufdemo.txt");

BufferedWriter bufw = new BufferedWriter(fw);//让缓冲区和指定流相关联。

for(int x=0;x<4;x++){

bufw.write(x+"abc");

bufw.newLine();//写入一个换行符,这个换行符可以依据平台的不同写入不同换行符。

bufw.flush;//对缓冲区进行刷新,可以让数据到达目的地中。

}

bufw.close();//关闭缓冲区,其实就是关闭具体的流。

-------------------------------------------------

BufferedReader:

FileReader fr = new FileReader("buf.txt");

BufferedReader bufr = new BufferedReader(fr);

String line = null;

while((line=bufr.readLine())!=null){//readLine方法返回的时候是不带换行符的。

System.out.println(line);

}

bufr.close();

------------------------------------------------------

//记住,只要一簇键盘录入,就用这句话。

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//输出到控制台

String line = null;

while((line=bufr.readLine())!=null){

if("over".equals(line))

break;

bufw.write(line.toUpperCase());//将输入的字符转成大写字符输出

bufw.newLine();

bufw.flush();

}

bufw.close();

bufr.close();

-------------------------------------------------------------

流对象:其实很简单,就是读取和写入。但是因为功能的不同,流的体系中提供N多的对象。那么开始时,到底该用哪个对象更为合适呢?这就需要明确流的操作规律。

流的操作规律:

1,明确源和目的

数据源:就是需要读取,可以使用两个体系:InputStream、Reader:

数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer:

2,操作的数据是不是纯文本数据?

如果是:数据源:Reader  数据汇:Writer

如果不是:数据源:InputStream 数据汇:OutputStream

3,虽然确定了一个体系,但是该体系有太多的对象,到底用哪个呢?

明确操作的数据设备。

数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)

数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。

4,需要在基本操作上附加其它功能吗?比如缓冲。

如果需要就进行装饰。

转换流特有功能:转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。

转换流的最强功能就是基于 字节流+编码表。没有转换,没有字符流。

发现转换流有一个子类就是操作文件的字符流对象:

InputStreamReader

|--FileReader

OutputStreamWriter

|--FileWriter

想要操作文本文件,必须要进行编码转换,而编码转换动作转换流都完成了。所以操作文件的流对象只要继承自转换流就可以读取一个字符了。

但是子类有个局限性,就是子类中使用编码是固定的,是本级默认的编码表,对于简体中文版的系统默认码表是GBK.

FileReader fr = new FileReader("a.txt");

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");

以上两句代码功能一致,

如果仅仅使用平台默认码表,就使用FileReader fr = new FileReader("a.txt");//因为简化。

如果需要指定码表,必须用转换流。

转换流=字节流+编码表。

转换流的子类FileReader =字节流+默认编码表

凡是操作设备上的文本数据,涉及到编码转换,必须是使用转换流。

------------------------------------------------------------------------------------------

File类:将文件系统的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹进行操作。这些是流对象办不到的,因为流只操作数据。

File类常见方法:

1,创建。

boolean createNewFile():在指定目录下创建文件,如果该文件存在,则不创建。而对操作文件的输出流而言,输出流对象已建立,就会创建文件,如果文件已存在,会覆盖。

boolean mkdir():创建此抽象路径名指定的目录。

boolean mkdirs():创建多级目录。

2,删除。

boolean delete():删除此抽象路径名表示文件或目录。

void deleteOnExit():在虚拟机退出时删除。

注意:在删除文件夹时,必须保证这个文件夹中没有任何内容,才可以将该文件夹用delete删除。

window的删除动作,是从里往外删。注意:java删除文件不走回收站。要慎用。

3,获取

long length():获取文件大小。

String getName():返回由此抽象路径名标识的文件或目录的名称。

String getPath():返回抽象路径名转换为一个路径名字字符串。

String getAbsolutePath():返回此抽象路径名的绝对路径名字符串。

String getParent():返回此抽象路径名父目录的抽象路径名,如果此路径名没有指定父目录,则返回null.

long lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。

File.pathSeparator:返回当前系统默认的路径分隔符,windows默认为“;”。

File.Separator:返回当前系统默认的目录分隔符,windows默认为"\"。

4:判断:

boolean exists():判断文件或者文件夹是否存在。

boolean isDirectory():测试此抽象路径名表示文件是否是一个目录。

boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。

boolean isHidden():测试此抽象路径名表示的文件是否是一个隐藏文件。

boolean isAbsolute():测试此抽象路径是否为绝对路径名。

5:重命名

boolean renameTo(File dest):可以实现移动的效果。剪切+重命名。

String[] list():列出指定目录下的当前的文件和文件夹的名称。包含隐藏文件。

如果用list方法的File对象中封装的是一个文件,那么list方法返回数组为null。如果封装的对象不存在也会返回null。只有封装的对象存在并且是文件夹示,这个方法才有效。

-------------------------------------------------------------------

递归:就是函数自身调用自身。

什么时候用递归呢?

当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。

简单说:功能内部又用到了该功能,但是传递的参数不确定。

递归的注意事项:

1:一定要定义递归的条件。

2:递归的次数不要过多。容易出现StackOverflowError栈内存溢出错误。其实递归就是栈内存中不端的加载同一个函数。

-------------------------------------------------------------------------------

Java.util.Properties一个可以将键值进行持久化存储的对象。Map--Hashtable的子类

Map

|--Hashtable

|-Properties:用于属性配置文件,键和值都是字符串类型。

特点:1:可以持久化存储数据。2:键值都是字符串。3:一般用于配置文件。

load():将流中的数据加载进集合。

原理:其实就是将读取的流和指定文件相关联,并读取一行数据,因为数据是规则的key=value,所以获取一行后,通过=对该行切割,左边就是键,右边就是值,将键、值存储到properties集合中。

store():写入各个项后,刷新输出流。

list():将集合的键值数据列出到指定目的地。

----------------------------------------------------------------------------------

6 高新技术:

网络编程

网络通信要素

1、IP地址:InetAddress

网络中的设备标识。

不易记忆,可用主机名。

本地回环地址:127.0.0.1主机名:localhost。

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IPDemo {

	public static void main(String[] args) throws UnknownHostException {
		InetAddress ip = InetAddress.getLocalHost();
		System.out.println(ip.getHostAddress());
		System.out.println(ip.getHostName());
		System.out.println("-----------");
		// 获取其它主机的ip地址对象
		ip = InetAddress.getByName("www.baidu.com");
		System.out.println(ip.getHostAddress());
		System.out.println(ip.getHostName());
	}
}

2、端口号

用于标识进程(应用程序)的逻辑地址,不同进程的标识。

有效端口:0~65535,其中0~1024系统使用或保留端口。

P.S.

当一台计算机A向另一台计算机B发送QQ信息时,首先路由器通过数据包中的IP地址定位该信息发送到哪一台机器。然后计算机B接收到数据包后,通过数据包中的端口号定位到发送给本机的QQ应用程序。

3、传输协议

常见协议:UDP、TCP。

UDP

将数据及源和目的封装成数据包中,不需要建立连接。

每个数据包大小在限制64K内。

因为无连接,是不可靠协议。

不需要建立连接,速度快。

应用案例:QQ、FeiQ聊天、在线视频用户的都是UDP传输协议。

UDP实例

udp发送端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class UDPSendDemo {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("发送端启动....");
		/*
		创建UDP传输的发送端。
		思路:
		1.建立udp的socket服务
		2.将要发送的数据封装到数据包中。
 		3.通过udp的socket服务将数据包发送出去。
		4.关闭socket服务
		*/
		//1.udp socket服务。使用DatagramSocket对象
		//如果发送端端口未指定,就会随机分配未被使用的端口。
		DatagramSocket ds = new DatagramSocket(8888);
		
		//2.将要发送的数据封装到数据包中。
		String str = "udp 传输演示,哥们来了!";
		
		//使用DatagramPacket将数据封装到该对象包中。
		byte[] buf = str.getBytes();
		
		DatagramPacket dp = new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.1.110"),10000);
		
		//3.通过udp的socket服务将数据发送出去,使用send方法。
		ds.send(dp);
		//4.关闭资源
		ds.close();
	}
}
udp接受端
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceDemo {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("接收端启动");
		/*
		 * 建立UDP接收端的思路
		 * 思路:
		 * 1.建立udp的socket服务,因为是要接收数据,必须要明确一个端口号。
		 * 2.创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据。
		 * 3.使用socket服务的receive方法将接收的数据存储到数据包中。
		 * 4.通过数据包的方法解析数据包中的数据。
		 * 关闭资源。
		 * */
		
		//1.建立udp socket服务
		DatagramSocket ds = new DatagramSocket(10000);
		//2.创建数据包
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf,buf.length);
		//3.使用接收方将数据存储到数据包中。
		ds.receive(dp);//阻塞式的。
		//4.通过数据包对象方法,解析其中的数据,比如:地址,端口,数据内容
		String ip = dp.getAddress().getHostAddress();
		//获取的端口号是发送端的端口号。
		int port = dp.getPort();
		String text = new String(dp.getData(),0,dp.getLength());
		System.out.println(ip+":"+port+":"+text);
		
		//5.关闭资源
		ds.close();
	}
}

TCP

建立连接,形成传输数据通信。

在连接中进行大数据量传输。

通过三次握手完成连接,是可靠协议。

必须建立连接,效率稍低。

应用案例:FTP、File Transfer Protocol(文件传输协议)

TCP实例

tcp客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo {

	public static void main(String[] args) throws UnknownHostException, IOException {
		Socket socket = new Socket("127.0.0.1",10002);
		OutputStream out = socket.getOutputStream();
		out.write("tcp演示:哥们又来了".getBytes());
		//读取各户端返回的数据,使用Socket读取流。
		InputStream in = socket.getInputStream();
		byte[] buf = new  byte[1024];
		int len = in.read(buf);
		String text = new String(buf,0,len);
		System.out.println(text);
		socket.close();
	}
}
tcp服务端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {

	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(10002);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		String text = new String(buf,0,len);
		System.out.println(ip+":"+text);
		
		//使用客户端socket对象的输出流输出流给客户端返回数据
		OutputStream out = s.getOutputStream();
		out.write("收到".getBytes());
		s.close();
		ss.close();
	}
}

反射

反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。

反射的好处:大大的增强了程序的扩展性。

反射的基本步骤:

1、获取Class对象,就是获取到指定的名称的字节码文件对象。

2、实例化对象,获得类的属性、方法或构造函数。

3、访问属性、调用方法、调用构造函数创建的对象。

获取这个Class对象,有三种方式:

1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

3:使用的Class类中的方法,静态的forName方法

指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

//1.根据给定的类名来获得  用于类加载

String classname = "cn.itcast.reflect.Person";//来自配置文件

Class class = Class.forName(classname);//此对象代表Person.class

//2.如果拿到了对象,不知道是什么类型  用于获得对象的类型

Object obj = new Person();

Class clazz1 = obj.getClass();//获得对象具体的类型

//3.如果是明确地获得某个类的Class对象  主要用于传参

Class clazz2 = Person.class;

反射的用法:

1、需要获得java类的各个组成部分,首先要获得类的Class对象,获得Class对象的三种方式:

Class.forName(classname) 用于做类的加载

obj.getClass() 用于获得对象的类型

类名.class          用于获得指定的类型,传参用

2、反射类的成员方法:

Class clazz = Person.class;

Method method = clazz.getMethod(String name,Class<?>... parameterTypes);

method.invoke(Object obj,Object... args);//obj是该类对象

3、反射类的构造函数:

实例化有参数的构造函数

 Constructor con = clazz .getDeclaredConstructor(Class<?>... parameterTypes)//通过字节码文件获取到构造器

con.newInstance(Object... initargs)//使用构造器实例化对象

实例化无参的构造函数

Object o = clazz.newInstance();

4、反射类的属性:

Field filed = clazz.getDeclaredField(String name);

filed.setAccessible(true);

filed.set(Object obj,Object value);

获取了字节码文件对象后,最终都需要创建指定类的对象:

创建对象的两种方式(其实就是对象在进行实例化的初始化方式):

1,调用空参数的构造函数:使用了Class类中的newInstance()方法。

2,调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过构造函数的对象的newInstance(实际参数)进行对象的初始化。

综上所述,第二种方式,必须要先声明具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。

-------------------------------------------------------------------------

//如何生成获取字节码文件对象的实例对象。

Class clazz = Class.forName("cn.itcast.bean.Person");//类加载

//直接获得指定的类型

clazz = Person.class;

//根据对象获得类型

Object obj = new Person("zhangsan",19);

clazz = obj.getClass();

Object obj = clazz.newInstance();//实例化对象的方法调用就是指定类中的空参数构造函数,给创建的对象进行初始化。

//如果没有空参数的构造函数,那么只要获取指定参数的构造函数,用该类函数来进行实例化。

//获取一个带参数的构造器

Constructor constructor = clazz.getConstructor(String.class,int.class);

//想要对对象进行初始化,使用构造器的方法newInstance();

Object obj = constructor.newInstance("zhangsan",30);

//获取所有构造器。

Constructor[] constructors = clazz.getConstructors();//只包含公共的

constructors = clazz.getDeclaredConstructors();//包含私有的

for(Constructor con : constructors){

System.out.println(con);

}

-------------------------------------------------------------------------------------

反射指定类中的方法:

//获取类中所有的方法。

Class clazz = Class.forName("cn.itcast.bean.Person");

Mehtod[] methods = class.getMethods();//获取的是该类中的共有方法和父类中的共有方法。

methods = clazz.getDeclareMethods();//获取本类中的方法,包含私有方法。

fro(Method method : methods){

System.out.println(method);

}

//获取指定方法:

Class clazz = Class.forName("cn.itcast.bean.Person");

Method method = clazz.getMethod("show",int.class,String.class);//获取指定名称的方法。

//想要运行指定方法,当然是方法对象最清楚,为了让方法运行,调用方法对象的invoke方法即可,但是方法运行必须明确所属的对象和具体的实际参数。

Object obj = clazz.newInstance();

method.invoke(obj,39,"hehehe");//执行一个方法

//想要运行私有方法。

Class clazz = Class.forName("cn.itcast.bean.Person");

//想要获取私有方法。必须用getDeclearMethod();

Method method = clazz.getDeclaredMethod("method",null);

//私有方法不可以直接访问,因为权限不够。非要访问,可以通过暴力的方式。

method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问。

//反射静态方法。

Class clazz = Class.forName("cn.itcast.bean.Person");

Method method = clazz.getMethod("function",null);

method.invoke(null,null);

-----------------------------------------------------------------------------------

正则

正则表达式:其实是用来操作字符串的一些规则。

好处:正则的出现,对字符串复杂操作变得更为简单。

特点:将对字符串操作的代码用一些符号来表示。只要使用了指定的符号,就可以调用底层的代码对字符串进行操作。符号出现,简化了代码的书写。

弊端:符号的出现虽然简化了书写,但是却降低了阅读性。其实更多是用正则解决字符串操作问题。

组:用小括号表示,没定义一个小括号,就是一个组,而且有自动编号,从1开始。只要使用组,对应的数字就是使用该组的内容。别忘了,数组要加\\。

常见操作:

1,匹配:其实用的就是String类的matches方法。

String reg="[1-9][0-9]{4,14}"

boolean b = qq.matches(reg);//将正则和字符串关联对字符串进行匹配。

/*
	 * 演示匹配
	 * */
	public static void functionDemo_1()
	{
		//匹配手机号码是否正确
		String tel = "15800022335";
		String regex = "1[358]\\d{9}";
		boolean b = tel.matches(regex);
		System.out.println(tel+":"+b);
	
	}

2,切割:其实用的就是String类中的split方法。

/*
	 * 演示切割
	 * */
	public static void functionDemo_2()
	{
		String str = "zhangsna   lisi     wangwu";
		String[] names = str.split(" +");
		for(String name : names)
		{
			System.out.println(name);
		}
	}

3,替换:其实用的就是String类中replaceAll();

/* 
     * 演示替换 
     * */  
    public static void functionDemo_5()  
    {  
        String str = "abbbbcd11111efg";  
        //$表示前一个参数的第一组  
        str= str.replaceAll("(.)\\1+", "$1");  
        System.out.println(str);  
    }  

4,获取:

a,先要将正则表达式编译成正则对象。使用的是Pattern中静态方法compile(regex);

b,通过Pattern对象获取Matcher对象。Pattern用于描述正则表达式,可以对正则表达式进行解析。而将规则操作字符串,需要从新封装到匹配对象Matcher中。然后使用Matcher对象的方法来操作字符串。

如何获取匹配器对象呢?

通过Pattern对象中的matcher方法。该方法可以正则规则和字符串相关联。并返回匹配器对象。

c,使用Matcher对象中的方法即可对字符串进行各种正则操作。

/*
	 * 演示获取
	 * */
	public static void functionDemo_7()
	{
		String str = "da jia hao,ming tiam bu fang jia";
		//\\表示单词边界
		String regex = "\\b[a-z]{3}\\b";
		//1.将正则封装成对象
		Pattern p = Pattern.compile(regex);
		//2.通过正则对象获取匹配器对象
		Matcher m = p.matcher(str);
		//使用Matcher对象的方法对字符串进行操作
		//既然要获取三个字母组成的单词
		//查找:find()
		while(m.find())
		{
			System.out.println(m.group());
			System.out.println(m.start()+":"+m.end());
		}
	}

------------------------------------------------------------------------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值