记录生活中的点点滴滴

0%

java.util.Vector 动态数组

get(index)

addElement(OBject obj)

size()

栈:局部变量

堆:new出来的结构,数组

方法区:类的加载信息,静态变量,常量

static关键字的使用:

  • static:静态的

  • static可以用来修饰:属性,方法,代码块,内部类

  • 使用static修饰属性:类变量(或静态变量

  • 使用static修饰的变量被类的所有对象所共享,类的所有对象共用一个静态变量

    对比:不用static修饰的属性,称为:实例变量,每个对象拥有一份实例变量

       通过对象a修改某个实例变量,不会影响其他对象同名的实例变量的值。

    我们可以通过对象a去调用或修改静态变量的值,那抹会影响其他对象对此静态变量的调用

静态变量和实例变量在内存中分配的位置不同:

  • 实例变量,随着对象的创建而产生,分配在堆空间中
  • 静态变量,随着类的加载而产生的,分配在方法区里

静态变量的加载要早于对象的创建

   静态变量 非静态变量(实例变量)

类  可以  不可以

对象  可以   可以

使用static修饰方法:静态方法(随着类的加载而加载)

   静态方法 非静态方法(实例变量)

类   可以    不可以

对象   可以     可以

静态方法内:可以调用静态属性或者静态方法,不可以调用非静态属性和非静态方法

非静态方法内:可以调用非静态属性或者非静态方法,可以调用静态属性和静态方法

如何判断属性是否声明为:static? 是否需要类的多个对象类共享此属性;很多常量都声明为static 如何判断方法是否声明为:static? 操作静态变量的方法,工具类中的方法。(Math)

异常的体系结构:

  java.lang.Throwable

  —-Error:错误。不编写针对代码进行处理

   —–StackOverflowError

   —–OOM

  —-Exception:异常:可以编写针对性的代码进行处理

   —–编译时异常:编译时就不通过的异常,报出来的异常

   —–运行时异常(RuntimeException):编译通过,运行时不通过,报出来的异常

    | —–NullPointerException:空指针异常

    |—–ArrayIndexOutOfBoundsException:数组角标越界异常

     |—–ClassCastException:类型转换异常

     |—–NumberFormatException:数值格式化异常

     |—–InputMismatchException:输入的类型不匹配

     |—–ArithmeticException:算术异常

     |———-。。。

面试题:常见的异常?并举例说明

如何处理异常(Exception)?

 java提供了异常处理的:抓抛模型

 1.过程一:“抛”:程序在正常的执行过程中,一旦出现异常,就会在相应的代码处生成相应的异常类的对象。

     ▶并将对象抛出,异常出现位置后面的代码就不再执行。

     ▶异常出现位置的后面的代码不再执行

     异常对象产生的方式:①自动抛出 ②手动抛出(在方法内,使用throw + 异常类的对象)

​ 2.过程二:“抓”:看出是异常的处理的方法:try catch finally;throws

​ try{

​ //可能出现异常的代码 }catch(Exception el){

​ //处理异常的方式1 }catch(Exception e2){

​ //处理异常的方式2 }…

​ finally{ //一定要被执行的操作 }

​ 、

说明:

  • finally是可选的

  • 在执行try中的语句是时,一旦出现异常,就会抛出相应异常的对象

    此对象会在如下的catch中进行匹配,一旦匹配成功,就进入相应的

​ catch的代码块中进行相应的异常处理,一旦处理完成,就跳出整个

​ try-catch结构,不再执行其后的catch语句。

  • 多个catch语句中的异常类型说明:子类异常必须声明在父类异常的上面,

    否则编译不通过。如果多个异常类型没有子父类关系,则没有顺序要求。

  • 执行完catch语句以后,如果其结构还有操作,则可以正常执行。

  • 在try中定义的变量,其作用于仅限于try声明的一对{},出了此{},不可被调用

  • catch中常见的异常处理方:

     ①getMessage()返回一个String变量

     ②printStackTrace();打印异常产生的堆栈信息 总结:运行时异常

  • try-catch-finally 结构可以嵌套

关于try-catch-finally结构中finally的使用:

 1.可选的

 2.即使在catch中出现异常,try中有return;catch中有return;三种情况,finally中的代码也一定会执行!

  3.开发中的应用:IO流资源,网络Socket,数据库连接等,JVM不会自动进行资源的关闭和垃圾的回收,

  需要我们手动去释放资源。所以此操作必须声明在finally中。

异常的的处理方式二:throws + 异常类型

   格式:在方法的声明后,使用 “throws + 异常类型 ”,表示:一旦方法执行过程中,出现异常将此异常的对象抛出。

  1.上述出现的异常对象,会抛给方法的调用者。比如method1()在method()2

   调用,如果method()1出现异常,则此异常抛给了method()2。

  2.体会try-catch-finally:真正处理异常,一旦处理完,就不会影响后续代码执行

   throws:并没有真正的处理异常。

  3.总结:开发中如何选择使用哪种方式处理?

  • 如果父类被重写的方法没有throws的方式处理异常,则子类重写的方法也不能用 throws的 方式去处理异常,只能用try-catch-finally。
  • 在一个方法a中,调用了另外的3个方法,此3个方法通常是递进关系的。一般情况下, 此3个方法中如果出现异常,通常使用throws的方式处理异常。然后统一在方法a中 使用try-catch-finally进行处理。

规定:子类重写的方法抛出的异常类型不能大于父类被重写的方法抛出的异常

包装类Integer (parseInt) 将字符串转成整数

注解:代码里的特殊标记

 OVerride 重写

 Deprecated 过时

 SuppressWarnings 抑制编译器警告

元注解:解释说明当前注解的

单例设计模式:

 饿汉式

 懒汉式

类的成员之四:代码块(或初始化块)

  1. 代码块的使用:用来初始化类,对象的信息

  2. 代码块的分类:静态代码块 vs 非静态代码块

  3. 静态代码块:

    ①可以提供输出语句

    ②随着类的加载而执行,且只被加载一次

    ③使用:初始化类的加载信息

    ④内部只能调用当前类中静态的属性,方法。不能调用非静态的属性,方法

    ⑤如果定义了多个静态代码块,按照定义的先后顺序执行

    ⑥静态代码块执行的顺序要早于非静态代码块

    非静态代码块:

   随着对象的创建而执行

   每创建对象,都会执行一次

   使用:初始化对象的属性

   内部可以调用静态的:属性,方法。也调用非静态的属性,方法

   如果定义了多个非静态代码块,按照定义的先后顺序执行

   非静态代码块执行的顺序要晚于静态代码块

4.给属性赋值的位置的先后顺序:

  ①默认初始化

  ②显示初始化 / 在代码块中初始化

  ③构造器中初始化

  ④有了对象以后,通过“对象.属性”或“对象.方法”的方法,赋值

final关键字的使用:

  • final:最终的

  • final可以来修饰:变量,方法,类

  • final修饰类:此类不可以被继承,比如String / StringBuffer类

  • final修饰方法:此方法不能被重写,比如Object类的getClass

  • final修饰变量:此变量就是一个常量。比如:Math类中的PI

    使用final修饰属性,可以考虑的位置有:

     ①显示初始化

     ②代码块中

     ③构造器中使用final修饰形参,在方法调用时,在方法调用时,传递实参,给变量赋值,一旦复制,方法内不可以 修饰常量的值

  static final:所修饰的属性,称为全局常量

abstract关键字的使用:

  • abstract :抽象的

  • 可用来修饰的结构:类,方法

  • abstract修饰类:抽象类

    不可实例化

    仍然存在构造器。构造器的作用:便于子类实例化时进行调用

    通常情况下,我们会提供抽象类的子类,让子类实例化,调用父类的结构。  

    抽象类中不一定有抽象方法;抽象方法所在的类,一定是抽象类

  • abstract修饰方法:抽象方法(没有方法体)

    如果子类重写了父类的所有抽象方法,则此子类可以实例化

    如果子类没有重写父类的所有抽象方法,则子类仍为抽象类

  • 前提:抽象性使用的前提是类的继承性

模板方法的设计模式

接口的使用:

  1.接口(interface) 是与类(class)并列的结构

  2.如何定义一个接口,使用interface关键字

  3.接口中只能定义常量和抽象方法—–>JDK7.0及以前版本(JDK8.0接口中引入默认方法,静态方法)

   常量的定义:public static final修饰

   抽象方法的定义: public abstract修饰

  4.接口中不能声明构造器!接口不可以直接实例化的

  5.类与接口之间的关系:实现(implements)关系,实现接口以后,就获取了接口中声明的结构:常量,抽象方法。

   格式:class SubClass extends SuperClass implements InterfaceA

  6.类实现接口以后,要抹实现接口中的所有抽象方法,方可实例化

   要抹当前类声明为抽象类(因为内部包含从接口中获取的抽象方法)

  7.java规定:类可以实现多个接口—–>一定程度上,解决了java类的单继承的局限性

   8.java规定:接口与接口之间是继承关系,而且是可以多继承!

接口的使用:

 1.接口与具体的实现类之间存在多态性

 2.如何提供接口的匿名实现类,如何去创建匿名对象

 3.接口,实际上可以理解为定义了一套相应的功能的规范,标椎

接口的应用:

  • 工厂模式
  • 代理模式

java8规范: 接口可以定义静态方法,默认方法

  ①知识点1:接口中定义的静态方法,只能通过接口进行调用

  ②知识点2:通过实现类的对象,调用接口中的默认方法

  ③知识点3:如果类实现的接口和父类中,定义了同名同参数的方法,那抹子类在没有重写此方法的情况下

   默认调用的是父类中声明的方法。—–“类优先”原则

  ④知识点4:如果实现类实现了多个接口,接口中定义了同名同参数的方法,那抹此时对于实现类来讲,会出现接口冲突问题。

  解决方法:要求实现类必须重写接口中的方法。

  ⑤知识点5:如何在实现类的方法中调用接口中的默认方法

  接口.super.方法()

类的成员之五:内部类(InnerClass)

1.定义:java语言在一个类A的内部再定义了一个类B。

   将类B:称作内部类;类A:外部类

2.内部类,作为一个类:

  内部可以定义属性,方法,构造器等

  可以被final修饰

  可以被abstract修饰

    作为外部类的一个成员:

  可以被4种不同的权限修饰

   可以被static修饰

  可以调用外部类的结构:属性,方法等

3.内部类的分类:成员内部类(静态的;非静态的) vs 局部内部类

4.需要掌握的知识点:

  4.1 如何创建成员内部类的对象?

  4.2 如何调用外部类的结构?

  4.3 关于局部内部类在开发中的体现

部内部类的方法中调用局部内部类所在方法中定义的局部变量,要求此局部变量声明为final的。

在java7及以前的版本中,需要显示的声明为final。

在java中可以省略final的声明

Collections:用来操作集合框架(Collection / Map)的工具类

  • reverse(List):反转 List 中元素的顺序
  • shuffle(List):对 List 集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
  • sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素\
  • Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素 Object
  • object min(Collection)
  • Object min(Collection,Comparator)
  • int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  • void copy(List dest,List src):将src中的内容复制到dest中

  List dest = Arrays.asList(new Object[list.size()]);

  Collections.copy(dest, list);

  System.out.println(dest);

  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

list:线程不安全的。

List newList = Collections.synchronizedList(list);

newList:线程安全的。

1.java中的容器–在内存层面,对数据进行统一的存储和管理:数组 ;java集合

​ 扩展:数据的持久化:文件(.jpg;mp3); xml ; 数据库

2.数组在内存存储方面的特点:

  ①数组初始化以后,长度就确定了

  ②数组类型声明后,就决定了进行元素初始化的类型

弊端:数组初始化以后,长度就不可变了

  数组中提供的属性和方法很少,不便于进行添加,删除,插入等操作

  数组存储的数据是有序的,可以重复的—–>存储数据的特点单一

  String[] arr = new String[10]

  Object[]

3.集合框架

 java.util.Collection:单列数据

 |——-List子接口:存储有序的,可重复的数据—->“动态”数组

   |—–ArrayList:作为List的主要实现类,线程不安全的,效率高;底层使用数组

   |—–LinkedList:对于频繁的插入,删除操作,我们建议使用此类,效率高;底层使用双向链表实现

   |—–Vector:List的古老实现类,线程安全的,效率低;底层使用数组实现

​ [面试题] ArrayList,LinkList,Vector区别?

    共同点:ArrayList,LinkList,Vector都是List接口的实现类,存储的数据都是有序的,可重复的

       区别:如上

       List list = new ArrayList();

       list.add(..);

       …

       一旦添加元素超出底层数组的长度,就需要扩容,默认扩容需要为原来的1.5倍,同时

       需要将原有数组中的元素复制到新的数组中。

实际情况:需要存储80个数据到ArrayList中,建议:List list = new ArrayList(85);

   |——-Set子接口:存储无序的,不可重复的数据—->高中讲的“集合”

      |—- HashSet 主要实现类,底层实现:HashSet底层使用了HashMap

      |—- LinkedHashSet 是HashSet的子类,可以按照添加的顺序实现遍历

        (原因:在HashSet底层存储上的基础上,额外使用了一对指针,能够记录此Node元素的

         上一个元素和下一个元素) —> 对于频繁的遍历,效率高

      |—- TreeSet : 可以按照添加元素的指定属性的大小实现遍历。底层实现:红黑树

       TreeSet的使用

         1.向TreeSet中添加的元素必须是同一个类创建的对象

         2.TreeSet排序的方式:①自然排序 ②定制排序

         3.自然排序:

           ①要求添加的元素所在的类实现Compare接口

           ②重写接口中的CompareTo(Object obj)—>指明排序的规则

            如果此方法返回值0,则要新添加的元素添加不成功

           ③向TreeSet添加此实现类的对象即可

         定制排序:

           TreeSet的定制排序:

            1.提供Comparator接口匿名实现类的对象

            2.重写其中的compare(Object o1,Object o2),指明排序的规则

            3.将此实现类的对象作为参数传递到TreeSet的构造器中

            4.向TreeSet的对象中添加compare()方法中判断类的对象

 总结: 元素是否能add成功,是否能remove,是否contains…..

    都依赖于compareTo或者compare方法 与元素所在类的hasCode/equals无关

set作为Collection的子接口,没有定义额外的方法set:存储无序的,不可重复的元素

  1. 无序性!= 随机性.添加的元素,需要计算哈希值,此哈希值决定了在底层储存的位置,从存储位置上看, 是无序的

  2. 不可重复性:保证set集合中不同对象使用对象所属类的equals()方法判断的话,一定返回false。

  3. 如何向Set中添加一个元素?哈希算法

   向Set中添加元素a,首先通过hasCode(),计算元素的哈希值,此哈希值就决定了此元素在Set底层

   存储的位置,如果此存储位置上没有元素,则此元素a添加成功 ,如果此存储的位置上有元素b,则

   调用元素a所在类的equals()方法.将元素b作为参数传递过去,如果返回值为true,则表示元素

   a和元素b相同,添加不成功,如果返回值为false,则认为元素a和元素b不相同,此时元素b可以添

   加成功的.元素a和元素b使用链表存储(jdk7.0:a指向b;JDK8.0:b指向a)

 4.向Set中添加的元素,要求其所在的类要重写两个方法: equals() 和 hashCode()

 5.必须要求添加的元素所在的类中重写equals() 和 hashCode()保持一致

Map:存储的是双列数据:key-value

 1.所有的key构成的是集合是set:无序的,不可重复的

 2.所有value构成的是集合Collection:无序的,可以重复的

 3.一个key-value构成一个Entry

 4.所有的Entry构成的集合是Set:无序的,不可重复的

 HashSet的底层使用HashMap存储的

 HashMap的所有key构成的集合是HashSet

|—-HashMap:Map的主要实现类,线程不安全,效率高;可以存储null的key和value

   (存储结构:Jdk7.0数组+链表,Jdk8.0数组+红黑树)

  |—-LinkedHashMap:HashMap的子类,可以按照添加的顺序遍历,对于频繁的遍历效率

  (在HashMap存储的基础上,使用了一对指针,来记录添加元素的顺序)

|—-TreeMap:可以按照key的指定的属性进行排序,遍历,底层实现:红黑树

|—-Hashtable:Map的古老实现类:线程安全,效率低;不可以存储null的key和value

   |—-Properties:Hashtable的子类,常常用来处理属性文件,其key和value都是String类型的

Map常用方法:

 添加:put(Object key,Object value)

 修改:put(Object key,Object value)

 删除:Object remove(Object obj)

 长度:size()

 清空数据:clear()

 是否为空isEmpty()

1.遍历所有的key

1
2
3
4
5
6
7
8
9
  Set keySet = map.keySet();

Iterator iterator = keySet.iterator();

while(iterator.hasNext()){

System.out.println(iterator.next());

}

​ 2.遍历所有的value

1
2
3
4
5
6
7
Collection coll = map.values();

for(Object obj:coll){

System.out.println(obj);

}

​ 3.遍历所有的key-value

​ 1.方式一:

1
2
3
4
5
6
7
Set keySet1 = map.keySet();

for(Object key:keySet1){

System.out.println(key+"---->"+map.get(key));

}

​ 2.方式二:

1
2
3
4
5
6
7
8
9
Set entrySet = map.entrySet();

for(Object o:entrySet){

Map.Entry entry = (Map.Entry)o;

System.out.println(entry.getKey()+"********"+entry.getValue());

}

Map常用方法:

  • 添加:put(Object key,Object value)
  • 修改:put(Object key,Object value)
  • 删除:Object remove(Object obj)
  • 长度:size()
  • 清空数据:clear()
  • 是否为空isEmpty()

总结:

  增:put(Object key,Object value)

  删:Object remove(Object obj)

  改:put(Object key,Object value)

  查:get(Object key)

  长度:size()

  遍历:keySet() / values() / entrySet()List (index—>数据)/ Set(很少用)/ Map(key –> 数据)

说明:1.向List中添加自定义类的对象的话,要求此定义类要重写equals()方法

    2.补充:数据结构解决两个问题:

       1.数据之间逻辑关系:一对一,一对多,多对多…

       2.数据的存储结构:①顺序存储:一维数组 ②链式存储

4.测试Collection中的常用方法

​ ①size()返回集合中存储的元素的个数

​ ②add(Object obj) 将obj添加到当前的集合中

​ ③addAll(Collection coll) 将coll1集合中的所有元素添加到当前集合中

​ ④isEmpty() 判断当前集合是否为空

​ ⑤clear 清除当前集合

​ ⑥contains(Object obj) 判断当前集合中是否包含obj:调用了obj所在类的equals()方法

​ ⑦containsAll(collection coll) 当前集合是否包含coll中的所有元素

​ ⑧remove(Object obj):从当前集合中移除obj元素.仍然需要obj所在类的equals的方法

​ ⑨removeAll(Collection coll):差集:从当前集合中移除coll集合中的元素

​ ⑩retainAll(Collection coll):交集:获取当前集合和coll共有的元素

​ ⑪equals(Object obj):比较当前对象和obj是否相等。

​ ⑫hashCode():获取当前对象的哈希值

​ ⑬toArray():将集合转换成数组:Object[]

​ ⑭toArrays(T[] arr):略

​ ⑮Iterator():集合元素的遍历。迭代器

​ hasNext():判断是否还有下一个元素

​ next():①指针下移 ②将指针下移以后集合位置上的元素返回

5.规定:如果集合中存储自定义类的对象,要求自定义重写equals方法

6.集合:很常用。

  掌握点:层次一:选择合适的集合类实现数据的保存,调用其内部的相关方法

      层次二:不同的集合类底层的数据结构为何?如何实现数据的操作的:增删改查等。

集合的遍历:

 方式一:使用Iterator实现

 方式二:增强for循环(foreach循环)

     for(集合元素的类型 局部变量 : 集合引用)

List:

在Collection的基础上,新增的方法:

  • void add(int index, Object ele):在index位置插入ele元素
  • boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
  • Object get(int index):获取指定index位置的元素
  • int indexOf(Object obj):返回obj在集合中首次出现的位置.如果不存在,返回-1.
  • int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置.如果不存在,返回-1.
  • Object remove(int index):移除指定index位置的元素,并返回此元素
  • Object set(int index, Object ele):设置指定index位置的元素为eleList
  • subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开区间的子集合
  • substring(int from ,int to) / read(int from,int length)

​ 总结:List中的常用方法:

   增:add(Object obj)

   删:remove(Object obj) / remove(int index)

   改:set(int index, Object ele)

   查:get(int index)

   插:add(int index, Object ele)

   遍历:iterator();增强for;for

   长度:size()

泛型的应用:

 1.JDK 5.0 新增的特性

 2.主要内容:

  2.1 在集合中使用泛型

  2.2 如何自定义泛型类,泛型接口,泛型方法(理解)

  2.3 泛型在继承上的体现(掌握)

  2.4 通配符的使用(掌握)

在集合中使用泛型的情况

在集合中使用泛型

 1.在Java的集合中,声明的接口或者类已经声明泛型

 2.我们在实例化接口时,可以指明泛型的类型

 3.不能使用基本数据类型,需要使用对应的包装类替换

 4.一旦创建对象时,使用了泛型,则通过对象调用方法,属性时,如果方法或属性使用了类的泛型, 则此时泛型类型就是对象实例化时候的类型

 5.如果实例化时候,不指明泛型参数,则默认是Object类型

自定义泛型类:

 仿照List去创建

 1.在类的声明后面,指明泛型参数,参数通常使用:T E K V

 2.在类的属性,方法,构造器中,可以使用类的泛型参数

  • 使用了类的泛型参数的方法,不能声明为static的
  • 不能在try-catch中使用泛型参数表示异常类型

关于自定义泛型类,泛型接口,泛型方法的使用

 自定义泛型类的使用:

  1.在实例化泛型类时,可以指明泛型的参数类型

  2.提供泛型类的子类时,可以指明泛型的参数类型.比如:SubOrder1类

泛型在继承上的体现

  1.如果A类是B类的父类,则List与List是没有子父类的关系的

   扩展:则G 和 G没有子父类关系!

  2.如果A类是B类的父类,则A 是 B的父类

通配符: ? 的使用:

  A类是B的父类,则G 和 G 的公共父类为G<?>

 关于数据的读写问题

 写入数据:不允许向使用通匹配符的集合中写入数据,除非可以写入null

 读取数据:可以从使用了通配符的集合中读取数据。读取的数据的类型默认是Object

有限制条件的通配符的使用?

? extends A:举例:List<? extends A> 可以作为List或者List的父类,其中B类是A类的子类?

? super A: 举例:List<? super A> 可以作为List或List的父类,其中B类是A类的父类

File类:

  1.java.io包下定义的

  2.一个File类的对象,既可以表示一个文件(.txt,.mp3,.avi,mp4,.doc),也可以表示一个文件目录。

  3.File类中只涉及到文件或文件目录的新建、删除、长度、修改时间、重命名等操作。没有涉及到对文件内容的修改。如果需要对文件内容进行修改的话,需要使用流。

  4.File类的对象常常作为流的构造器的参数出现。

  5.File类的对象代表着流资源读取或写入到的文件。

File类的实例化

  绝对路径:包含盘符在内的文件或文件目录的完整路径

  相对路径:相较于某一层文件路径来讲。比如:在Eclipse中的相对路径是相较于当前工程的。

两个构造器:

  File(String pathname)

  File(String parent,String pathname)

获取文件名:

getName()

getPath()

getAbsoluteFile()

getAbsolutePath()

getParent()

toPath()

renameTo(File newName)

file1.renameTo(File file2):file1重命名为file2是否成功

如果希望返回值为true.则必须:file1对应的物理磁盘上的文件需要存在,且file2对应的物理磁盘上的文件不存在。

文件检测:

exists()

canWrite()

canRead()

isFile()

isDirectory()

获取文件常规信息:

lastModified()

length()

操作文件相关的:

​ createNewFile():在物理磁盘上创建指定路径的文件

​ delete():删除物理磁盘上指定路径的文件

操作文件目录相关的:

​ mkdir()/mkdirs():如果要创建的文件目录的上层目录存在,则二者没有区别。

​ 如果要创建的文件目录的上层目录不存在,mkdir()创建不成功,mkdirs()创建成功。

delete():删除物理磁盘上指定路径的文件目录list()listFiles()

list() / listFiles()

一、流的分类

 1.流的流向:输入流、输出流

 2.流中数据单位:字节流、字符流

 3.流的角色不同:节点流、处理流

二、 抽象基类 节点流(或文件流) 缓冲流(处理流的一种):提高数据读写效率

​ InputStream FileInputStream(read(byte[])) BufferedInputStream(read(byte[])

​ OutputStream FileOutputStream(write(byte[],0,len)) BufferedOutputStream(write(byte[],0,len)

​ Readed FileReader(read(char[])) BufferedReader(read(char[]) / readLine())

​ Writer FileWriter(write(char[],0,len)) BufferedWriter(write(char[],0,len)

从指定文件中读取数据到控制台上

 1.要去读的文件一定要存在的,否则报FileNotFoundException

 2.因为需要保证流的资源关闭,所以异常的处理需要使用try-catch-finally

字节流:

 输入流:FileInputStream

 1.创建一个文件,指明读取数据的来源

 2.将file对象作为参数传递到流的构造器中,创建一个字节的输入流:FileInputStream

 3.read():读取文件中的下一个字节。如果到达文件末尾的话,返回-1

 4.关闭资源

输出流:FileOutputStream

 1.造文件

 2.造流:输出流

 3.写出数据 getBytes() 字符串—>字节数组

 4.关闭资源

  * 如果输出的文件不存在,则在输出执行的过程中,自动创建此文件
  * 如果输出的文件存在:如果使用构造器:FileOutputStream(file)是对已存在的文件的覆盖,

​ 如果使用构造器:FileOutputStream(file,true)是在已有文件内容的基础上,继续写入内容

字符流

  FileReader 和 FileWriter的使用:只能用来处理文本文件的。

 FileInputStream 和 FileOutputStream:适合用来处理非文本文件:.avi , .mp3, .jpg, .doc

1.造文件

2.造流:字符的输入流、字符的输出流

3.读取数据并写出

4.关闭资源

缓冲流的使用。

 1.缓冲流是处理流的一种

 2.作用:提高数据的读写效率

 3.类: 处理非文本文件:

   BufferedInputStream

   BufferedOutputStream

    处理文本文件:

   BufferedReader

   BufferedWriter —>readLine 读取一行

           —>newLine 开始新的一行

理流之二:转换流

 1.转化流的作用:能够实现字节流与字符流之间的转换

 2.涉及到的流:

   InputStreamReader:实现字节的输入流转换为字符的输入流

   OutputStreamWriter:实现字符的输出流转换为字节的输出流

  编码的过程:字符串、字符数组—>字节数组

  解码的过程:字节数组—->字符串、字符数组

3.常见的编码集:

 ASCII:美国标准信息交换码,用一个字节的7位可以表示。

 ISO8859-1:拉丁码表。欧洲码表. 用一个字节的8位表示。

 GB2312:中国的中文编码表。

 GBK:中国的中文编码表升级,融合了更多的中文文字符号。

 Unicode:国际标准码,融合了多种文字。 所有文字都用两个字节来表示,Java语言使用的就是unicode

 UTF-8:最多用三个字节来表示一个字符

处理流之三:标准的输入、输出流

 System.in:标准的输入流,默认从键盘输入

 System.out:标准的输出流,默认从显示屏输出

  System.setIn():重新指定输入的位置

 System.setOut():重新指定输出的位置

处理流之四:打印流 PrintStream 和 PrintWriter

处理流之五:数据流 DataInputStream 和 DataOutpuStream

处理流之六:对象流

 1.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中, 也能把对象从数据源中还原回来。

 2.涉及到的流:ObjectInputStream 和 ObjectOutputStream

 3.对象序列化机制:允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象.

提供一个自定义类,实现序列化机制。

 要求:1.自定义类实现Serializable接口

    2.需要给当前的类声明全局的常量:serialVersionUID

    3.要求类的属性也是可序列化的。 (默认情况下:String、基本数据类型都是可序列化的)

    注意:不能序列化static和transient修饰的成员变量

RandomAccessFile的使用:随机存取文件流

 1.RandomAccessFile在java.io包下声明,直接继承于Object类

 2.既可以作为输入流,又可以作为输出流。

 3.如果输出到的文件不存在,则会在输出的过程中,自动创建此文件 。 如果输出到的文件存在,

  则不是对文件的覆盖,而是对文件内容的覆盖。(默认从头覆盖)

 4.实现数据的“插入”

jdk 7.0 时,引入了 Path、Paths、Files三个类。

 1.此三个类声明在:java.nio.file包下。

 2.Path可以看做是java.io.File类的升级版本。也可以表示文件或文件目录,与平台无关

 3.如何实例化Path:使用Paths.

  static Path get(String first, String … more) : 用于将多个字符串串连成路径

  static Path get(URI uri): 返回指定uri对应的Path路径

Path:

String toString() : 返回调用 Path 对象的字符串表示形式

boolean startsWith(String path) : 判断是否以 path 路径开始

boolean endsWith(String path) : 判断是否以 path 路径结束

boolean isAbsolute() : 判断是否是绝对路径

Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径

Path getRoot() :返回调用 Path 对象的根路径

​ Path getFileName() : 返回与调用 Path 对象关联的文件名

​ int getNameCount() : 返回Path 根目录后面元素的数量(层数)

​ Path getName(int idx) : 返回指定索引位置 idx 的路径名称

​ Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象

​ File toFile(): 将Path转化为File类的对象

Files

Path copy(Path src, Path dest, CopyOption … how) : 文件的复制

​ >要想复制成功,要求path1对应的物理上的文件存在。path1对应的文件没有要求。

​ Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING); 当已存在时做覆盖

Path createDirectory(Path path, FileAttribute<?> … attr) : 创建一个目录

​ 要想执行成功,要求path对应的物理上的文件目录不存在。一旦存在,抛出异常。

Path createFile(Path path, FileAttribute<?> … arr) : 创建一个文件

​ 要想执行成功,要求path对应的物理上的文件不存在。一旦存在,抛出异常。

void delete(Path path) : 删除一个文件/目录,如果不存在,执行报错

void deleteIfExists(Path path) : Path对应的文件/目录如果存在,执行删除.如果不存在,正常执行结束

Path move(Path src, Path dest, CopyOption…how) : 将 src 移动到 dest 位置

要想执行成功,src对应的物理上的文件需要存在,dest对应的文件没有要求。

Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);

long size(Path path) : 返回 path 指定文件的大小

boolean exists(Path path, LinkOption … opts) : 判断文件是否存在

boolean isDirectory(Path path, LinkOption … opts) : 判断是否是目录

boolean isRegularFile(Path path, LinkOption … opts) : 判断是否是文件

boolean isHidden(Path path) : 判断是否是隐藏文件

​ >要求此path对应的物理上的文件需要存在。才可判断是否隐藏。否则,抛异常

boolean isReadable(Path path) : 判断文件是否可读

boolean isWritable(Path path) : 判断文件是否可写

boolean notExists(Path path, LinkOption … opts) : 判断文件是否不存在

StandardOpenOption.READ:表示对应的Channel是可读的。

StandardOpenOption.WRITE:表示对应的Channel是可写的。

StandardOpenOption.CREATE:如果要写出的文件不存在,则创建。如果存在,忽略 StandardOpenOption.CREATE_NEW:如果要写出的文件不存在,则创建。如果存在,抛异常

SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 获取与指定文件的连接,how 指定打开方式。

DirectoryStream newDirectoryStream(Path path) : 打开 path 指定的目录

InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象

OutputStream newOutputStream(Path path, OpenOption…how) : 获取 OutputStream 对象

jdk 7 提供基于try-catch的自动资源管理

 能够实现资源的自动关闭,需要满足:

  1.可以在一条 try 语句中管理多个资源,每个资源以“;” 隔开即可。

  2.需要关闭的资源,必须实现了 AutoCloseable 接口或其子接口 Closeable目的:不需要再使用finally,显式的关闭资源了。

赋值运算符 =

支持链式赋值 a = b = 99

复合赋值运算符 (+= , -= , /= , *=)

short a = 10;

a += 2 与 a = a +2 相似,有区别的

a += 2 相当于a自增,不会改变本身变量数据类型

a = a +2 因为整型常量默认是int,所以a+2,自动提升数据类型为int,会报错

真正开发中,如果希望变量自增1:

方式1: i = i + 1

方式2: i += 1

方式3: i++ (推荐)

真正开发中,如果希望变量自增2:

方式1: i = i + 2

方式2: i += 2 (推荐)

比较运算符: == != > < >= <= instanceof

比较运算符的结果都是布尔类型(boolean)

逻辑运算符:运算符操作的是boolean型变量,运算结果也是boolean类型

&逻辑与运算符 && 短路与

|逻辑或运算符 || 短路或

!逻辑非运算符 ^ 逻辑异或

&和&&运算结果相同,如果符号左边是true,两个运算符都要执行右边的运算

​ 如果符号左边是false,&仍然要执行右边的,&&不在执

​ 行符号右边的

|和||运算结果相同, 如果符号左边是true, |仍然要执行右边的,||不在执

​ 行符号右边的

​ 如果符号左边是false,两个运算符都要执行右边的运算

位运算符:操作的都是数值型变量

<< >> >>>(无符号右移) & | ^ ~

<< 规律:在一定范围内,每左移一位,相当于数值*2,过犹不及(截断是让数值变的更小)

。>> 规律:在一定范围内,每右移一位,相当于数值/2,过犹不及。

。>>>:右移以后最高位拿0补

三元运算符:(条件表达式)?表达式1:表达式2

​ 表达式1和表达式2的数据类型要一致(满足自动类型提升也可以)

三元运算符一定可以转换为if else,反之不成立

顺序结构:

前向引用

分支结构:

if(条件表达式){

​ 执行代码块

}

if(条件表达式){

​ 执行代码块1

}

else{

​ 执行代码块2

}

if(条件表达式1){

​ 执行代码块1

}

else if(条件表达式2){

​ 执行代码块2

}

else{

​ 执行代码快n

}

1.else:结构可选的

2.如果两个条件表达式没有公共的交集,此时两个else if结构,可以交换结构

.如果两个条件表达式有公共的交集,要求范围小的条件表达式放在条件表达式的上面,

​ 此时两个条件表达式才有可能都被执行到

从键盘获取数据

  • 导包

    import java.util.Scanner;

  • 实例化Scanner

  • 调用相关方法,获取不同类型的变量

    next 字符串

    nextInt 整数

    nextDouble double

    nextFloat float

    nextBoolean 布尔类型

    Scanner类中没有从键盘获取char的方法

    用户输入的变量类型与调用的方法类型需要一致,否则,报inputMismatchException

一、继承Thread的方式

  1.提供一个继承于Thread类的子类

  2.重写Thread类的run():将创建的线程要执行的操作,声明在run()中。

  3.实例化Thread子类

  4.调用子类对象的start()

Thread类的常用方法的测试

  1.run():Thread的子类一定要重写的方法。将此分线程要执行的操作,声明在run()中

   2.start():要想启动一个分线程,就需要调用start():①启动线程②调用线程的run()

   3.currentThread():静态方法,获取当前的线程

   4.getName():获取当前线程的名字

   5.setName(String name):设置当前线程的名字

   6.yield():当前线程调用此方法,释放CPU的执行权

   7.join():在线程a中调用线程b的join()方法:只用当线程b执行结束以后,线程a结束阻塞状态,继续执行。

   8.sleep(long millitimes):让当前的线程睡眠millitimes毫秒

   9.isAlive():判断当前线程是否存活

  10.线程的优先级:

     MAX_PRIORITY:10

    NORM_PRIORITY:5 —默认优先级

    MIN_PRIORITY:1

​   设置优先级:setPriority(int priority);

​   获取优先级:getPriority();

设置优先级以后,对高优先级,使用优先调度的抢占式策略,抢占低优先级的执行。但是并不意味着高优 先级的线程一定先于低优先级的线程执行,而是从概率上来讲,概率更大而已。

线程通信:wait() / notify() / notifyAll() —->java.lang.Object类中定义的方法

一:继承Thread的方式

   1.提供一个继承Thread类的子类

   2.重写Thread类run():将创建的线程要执行的操作,声明在run()中

   3.实例化Thread子类

   4.调用子类对象的start()方法

创建多线程的方式二:

   1.创建一个实现Runnable接口的类

   2.实现Runnable的run()

   3.创建当前实现类的对象

   4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

   5.通过Thread类的对象调用其start()

对比继承Thread类和实现Runnable接口的方式

   1.联系:public class Thread implements Runnable

   2.相同点:启动线程,使用的是同一个start()方法

   3.对比:实现Runnable接口要好一些.

 原因:①不影响类的继承,因为类是单继承的

    ②针对于有共享数据的操作,更适合使用Runnable的方式 ,换句话说,实现Runnable接口的方式,实现了代 码和数据的分离

   4.面试题:创建多线程有几种方法? 继承Thread类,实现Runnable接口,实现Callable接口,使用线程池

模仿车站买票程序。开启3个窗口卖票。总票数为100张。—–使用实现的方式

  1.问题:出现了重票和错票

  2.问题出现的原因:一个窗口在没有售完票的情况下,其他的窗口参与进来,操作ticket,导致ticket输出的错 误。

  3.解决的方案:当某一个窗口完全操作完ticket以后,其他窗口应该才被允许进来,继续操作ticket。

  4.java如何实现的?同步机制:①同步代码块 ②同步方法

   4.1 同步代码块:

​ synchronized(同步监视器){

​ //需要被同步的代码

​ }

   说明:需要被同步的代码:即为操作共享数据的代码

      共享数据:多个线程共同操作的数据。比如:ticket

      同步监视器:俗称:锁。 可以由任何一个类的对象充当。 要求:保证多个线程共用同一把锁!

   4.2 同步方法:将操作共享数据的方法,声明为同步的。此方法即为同步方法。

     使用同步方法解决实现方式的线程安全问题。

     1.默认的同步方法(非静态的)的锁是:当前对象,也就是this.

     2.默认的同步方法(静态的)的锁是:当前类本身.

      使用同步方法解决继承方式的线程安全问题:

     注意:继承的方式中,要慎用同步方法。

​ 5.好处:线程的同步机制,解决了线程的安全问题。

​ 6.劣势:在操作共享数据过程中,是单线程的。

模仿车站买票程序。开启3个窗口卖票。总票数为100张 —–使用实现的方式

  解决线程安全问题的方式三:ReentrantLock

  存在线程的安全问题,使用Lock的方式解决线程安全问题。

面试题:同步的方式和Lock的方式,解决线程安全方面的异同?

  同:解决了线程安全问题

  异:同步的方式:同步监视器在线程执行完操作共享数据的代码以后,自动释放

Lock的方式:需要显式的调用unlock()方法之后,才能保证其他线程操作共享数据。

死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁,是我们开发中需要规避的!

线程的通信:

  • wait():一个线程在执行过程中,一旦调用此方法,则此线程进入阻塞状态,等待其他线程来唤醒自己。

  • notify():一个线程在执行过程中,一旦调用此方法,则会唤醒被wait()的一个线程。高优先级的要优先被唤醒。

  • notifyAll():一个线程在执行过程中,一旦调用此方法,则会唤醒所有被wait()的线程。

   例题:使用两个线程打印 1-100. 线程1, 线程2 交替打印

注意点:1.此三个方法必须使用在同步中。

    2.此三个方法的调用者是同步监视器!否则,如果三个方法的调用者不是同步监视器,报异常。

    3.此三个方法定义在Object类

面试题:sleep() 和 wait() 的异同?

  1.方法声明在哪? Thread:sleep() Object:wait()

  2.共同点:使得当前线程进入阻塞状态

  3.使用的范围要求:sleep()使用没有情境的要求;wait()必须使用在同步代码块或同步方法中

  4.都使用在同步当中的话:wait()需要唤醒:notify()/notifyAll(); sleep():不会释放锁;wait()会释放锁

String:字符串

   1.字符串声明的数据,会存储在字符串常量池中。第一次声明时,需要创建相应的字符串。之后,如果声明的变量,其值与之前存在的字符串内容相同,则直接引用现成的字符串。

   2.面试题:String s3 = new String(“javaEE”);创建的对象,在内存中生成了几个对象?

String:代表着不可变的字符序列。

   1.String类的声明public final class String implements java.io.Serializable, Comparable,     CharSequence

     ①String声明为final,不可被继承。

     ②实现Serializable:表明String可序列化。浏览器/客户端<—>服务器端 进程1<—->进程2       “{name=Tom,age=12}” JSON:本质就是String

     ③String重写了hashCode()/equals():常常将Map的key声明为String型。

     ④实现Comparable接口:String可以比较大小。

     ⑤实现CharSequence接口:String的底层声明了char[] value数组。

   2.如何理解String的不可变性:

     ①向现有的字符串后添加新的字符串,必须声明新的字符串空间

     ②将现有的字符串替换为新的字符串,必须声明新的字符串空

     ③只替换现有字符串中的指定某个字符,也必须声明新的字符串空间

String类与其它结构的转换:

   1.String 与包装类、基本数据类型变量间的转换

    String–>包装类、基本数据类型:调用包装类Xxx的parseXxx(String s)方法

    包装类、基本数据类型 –>String:调用String的valueOf(xxx xxx);

   2.String 与 字节数组间的转换

    String –> 字节数组:调用String类的getBytes()

    字节数组–>String:new String(byte[] buffer,startIndex,length)

   3.String 与 字符数组间的转换

    String –> 字符数组:调用String类的toCharArray()

    字符数组 –>String:new String(char[] cbuf,startIndex,length)

  • public String substring(int startpoint):返回当前字符串中从startPoint位置开始,到末尾的子字符串。

  • public String substring(int start,int end):返回当前字符串中从startPoint位置开始,到end结束的左闭右开区间的子字符串。

  • pubic String replace(char oldChar,char newChar):将字符串中指定的所有oldChar替换为newChar.

  • public String replaceAll(String old,String new):将字符串中指定的所有old替换为new.

  • public String trim():去除字符串首尾的空格

  • public String concat(String str):连接两个字符串

  • public boolean contains(CharSequence s):判断当前字符串中是否包含s.

  • public String[] split(String regex)根据给定正则表达式的匹配拆分此字符串。

  • public int length():返回当前字符串的长度

  • public char charAt(int index):获取指定索引位置的字符

  • public boolean equals(Object anObject):比较两个字符串内容是否相等。

  • public int compareTo(String anotherString):比较两个字符串的大小

  • public int indexOf(String s):返回s在当前字符串中首次出现的位置。如果不存在,返回-1.

  • public int indexOf(String s ,int startpoint):

  • public int lastIndexOf(String s):返回s在当前字符串中末次出现的位置。如果不存在,返回-1.

  • public int lastIndexOf(String s ,int startpoint):

  • public boolean startsWith(String prefix):判断当前的字符串是否以指定的prefix字符串开始的

  • public boolean endsWith(String suffix):判断当前的字符串是否以指定的suffix字符串结束的

  • public boolean regionMatches(int firstStart,String other,int otherStart ,int length) ?

面试题:

  String:不可变的字符序列;底层使用char[]存储

  StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储

  StringBuilder:可变的字符序列;线程不安全的,效率高,(jdk 5.0新增);底层使用char[]存储

类比:String —>数组; StringBuffer —>Vector StringBuilder —>ArrayList

   ArrayList list = new ArrayList();

   list.add(123);//new Object[10];

   ….

   扩容:1.5倍的方式扩容。

   这里:

    String str = new String();//new char[0];

    str.length();

    String str1 = new String(“abc”);//new char[]{‘a’,’b’,’c’};

   对比:

    StringBuffer s1 = new StringBuffer();//char[] value = new char[16]

    StringBuffer s2 = new StringBuffer(10);//char[] value = new char[10]

    s1.append(“abc”);//value[0] = ‘a’,value[1] = ‘b’,value[2] = ‘c’;

     …

       每次添加时,都需要判断底层的char[]是否能够盛装下新要添加的字符串。

       如果不能盛装下,需要扩容。默认扩容为原来的2倍 + 2.

    启示:StringBuffer s1 = new StringBuffer(int capacity);开发中建议使用此构造器。

StringBuffer中的方法:

  • StringBuffer append(String s),

  • StringBuffer append(int n) ,

  • StringBuffer append(Object o) ,

  • StringBuffer append(char n),

  • StringBuffer append(long n),

  • StringBuffer append(boolean n),

  • StringBuffer insert(int index, String str)

  • public StringBuffer reverse()

  • StringBuffer delete(int startIndex, int endIndex):删除当前可变字符串中从startIndex到endIndex结束的左闭右开区间的数据。

  • public char charAt(int n )

  • public void setCharAt(int n ,char ch)

  • StringBuffer replace( int startIndex ,int endIndex, String str)

  • public int indexOf(String str)

  • public String substring(int start,int end)

  • public int length()

总结:

  增:append(Xxx xxx)

  删:delete(int startIndex, int endIndex

  改:setCharAt(int n ,char ch) / replace( int startIndex ,int endIndex, String str)

  查:charAt(int n)

  插:insert(int index, String str)

  长度:length()

  遍历:使用for + charAt()