JAVA基础

1.JRE和JDK

 JRE(Java Runtime Environment ):Java运行环境,包括Java虚拟机和Java所需的核心类库等。

JDK(Java Development Kit):Java开发工具包,供开发人员使用,JDK中包括了JRE。其中的开发工具包括:编译工具(javac.exe )、打包工具(jar.exe等)

2.静态(static)
用法:修饰符用来修饰成员(成员变量、成员函数)
static修饰内容被对象所共享。
被static修饰的成员可以直接被类名调用(类名.静态成员)
特有数据随对象存储
static特点:1.随着本类的加载而加载,随着类的消失而消失。2.优先于对象存在(静态先存在,对象后存在)。3.被所有对象所共享。4.可以直接被类名所调用。
实例变量和类变量区别:1.存放位置:类变量随类的加载存在于方法区中。实例变量随对象的建立而存在于堆内存中。2.生命周期:类变量生命周期长随着类的消失而消失。实例变量生命周期随着对象的消失而消失。
静态使用注意事项:1.静态方法只能访问静态成员,非静态方法既可以访问静态也可以访问非静态。2.静态方法中不可以定义this super关键字,因为静态优先于对象存在所以静态方法中不可以出现this。3.主函数是静态的。
静态的利弊:利:对对象的共享数据进行单独空间的存储节省空间;可以直接被类名调用;
弊:生命周期过长;访问出现局限性。
什么时候使用静态?1.当对象中出现共享数据时,该数据被静态所修饰。对象中的特有数据要定义成非静态存在于堆内存中。
什么时候定义静态函数?当功能内部没有访问到非静态数据(对象的特有数据那么该功能可以定义成静态的)
每一个应用程序中都有共性的功能可以将这些功能进行抽取独立封装以便复用。
将方法都静态后可以方便使用但该类还可以被其他程序建立对象为了严谨强制让该类不能建立对象可以通过将构造器函数私有化完成。
静态代码块:static{  静态代码块中执行的语句}  特点:随着类的加载而执行用于给类进行初始化。
3.抽象类
当多个类中出现功能相同,但是功能体不同,可以进行向上抽取,这时,只抽取功能定义,不抽取功能主体。
抽象的特点:1.抽象方法一定在抽象类中。2.抽象方法和抽象类都必须被abstract关键字修饰。3.抽象类不可以用new创建对象,因为调用抽象方法没意义。4.抽象类中的抽象方法要被调用,必须有子类复写其所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么子类仍然是抽象类。
抽象类比一般类多了抽象函数。抽象类不可以被实例化。抽象只能用来修饰类和方法。
特殊:抽象类可以不创建抽象方法,这样做仅仅是不让该类创建对象。
模板方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分,在使用不确定的部分,那么这时就将不确定的部分暴漏出去,由该类的子类去完成。
4.this用法
this代表它所在函数所属对象的引用(简单说:哪个对象在调用this所在函数。this就代表哪个对象)
this的应用:当定义类中功能时该函数内部要用到调用该函数的对象时,这时用this来表示这个对象但凡本类功能内部使用了本类对象都用this表示。
this语句用于构造函数之间互调。this语句只能放在构造函数的第一行,因为初始化语句要先执行
5.关键字final
final:最终,作为一个修饰符可修饰类、方法、变量。被final修饰的类不可以被继承,为了避免被继承,被子类复写功能。被final修饰的方法不能被复写。被final修饰的变量是常量,只能赋值一次,既可以修饰成员变量也可以修饰局部变量。
常量的书写规范:所有字母大写,当有多个单词组成时单词间通过下划线(_)连接。
6.接口(interface)
接口:可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。
class用于定义类。
interface用于定义接口。
接口定义时格式特点:1.接口中常见定义,常量,抽象方法。2.接口中的成员都有固定修饰符。常量:public static final  ;方法:public abstract。记住:接口中的成员都是public的。
接口不可以创建对象,因为有抽象方法。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类。
接口可以被类多实现。
接口之间可以多继承。
接口的特点:1.接口是对外暴露的规则。2.接口是程序的功能扩展。3.接口可以用来多实现。4.类与接口之间是实现关系而且类可以继承一个类的同时实现多个接口。5.接口与接口之间可以有多继承关系。
基本功能定义在类中,扩展功能定义在接口中。
事物之间的关系:聚集:has-a(一个事物中包含另一事物);聚合:同类事物组成一个集合(如球员与球队的关系);组合:如手是身体的一部分。
7.构造函数
构造函数特点:1.函数名与类名相同;2.不用定义返回类型;3.不可以写return语句;
作用:给对象进行初始化
对象一建立构造函数就被执行
当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数,当在类中自定义构造函数后默认的构造函数就没有了。
构造代码块:格式:{ 执行语句};作用:给对象进行初始化,对象一建立就运行而且优于构造函数执行。 
构造代码块给所有的对象进行统一初始化而构造函数是给对应的对象初始化。构造代码块中定义的是不同对象共性初始化内容。
构造函数可以被私有化。
8.理解面向对象
面向过程强调的是功能行为。
面向对象:将功能进行封装进对象强调具备了功能的对象。
1.面向对象是相对于面向过程而言的。
2.面向对象和 面向过程都是一种思想。
3.面向过程强调的是功能行为。
4.面向对象将功能封装进对象,强调具备了功能的对象。
5.面向对象是基于面向过程的。
9.单例模式(Singleton)
饿汉式(先初始化对象,Singleton一进内存就已经创建好了对象)(开发一般用饿汉式):
[java] class Singleton{
           private static Singleton s=new Singleton();
          private Singleton() {}
          public static Singleton  getInstance()
          {
               return s;
          }
         }

懒汉式(对象时方法调用时才被初始化,也叫做对象的延时加载。Singleton进内存时对象还没有存在,只有调用了getInstance方法时才建立对象)
[java] class Singleton{
           private static Singleton s=null;
          private Singleton() {}
          public static synchronized Singleton  getInstance()
          { 
               if(s==null)
               {
                  s=new Singleton();    
               }
               return s;
          }
         }
改进:
[java] class Singleton{
           private static Singleton s=null;
          private Singleton() {}
          public static  Singleton  getInstance()
          {
               if(s==null)
               {
                  synchronized(Singleton.class)
                    { 
                              if(s==null)
                            s=new Singleton();  
                      }
                   
               }
               return s;
          }
         }
使用原则;定义单例建议使用饿汉式。
10.封装
封装;指隐藏对象属性和实现细节仅对外提供公共访问方式。
好处:1.将变化隔离;2.便于使用;3.提高重用性;4.提高安全性
封装原则:1.将不需要对外提供的内容隐藏起来;2.把属性都隐藏提供公共方法对其访问。
Java中的函数本身就是一个最小的封装体。
private私有权限修饰符,私有只在本类中有效。私有不是封装,私有仅仅是封装的一种表现形式。
成员变量都有默认值存储在堆内存中。
11.继承
继承:1.提高代码复用性。2.使类与类之间产生关系,有了这个关系才有了多态的特性。
注意:不要为了获取其他类的功能简化代码而继承,必须是类与类之间有所属关系才可以继承。所属关系 is-a。
java语言:只支持单继承,不支持多继承,因多继承会带来安全隐患(当多个父类中定义了相同功能,当功能内容不同时,子类不确定要运行哪一个。但是java保留了这种机制,并用另一种体现形式来完成表示:多实现。)
java支持多层继承。
1.变量:如果子类中出现非私有同名成员变量时,子类要访问本类中的变量用this,子类要访问父类中的同名变量用super。
this代表本类对象的引用,super代表父类对象的引用。
2.函数:当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样,这是函数的另一个特性重写(覆盖override)
3.子父类中的构造函数:先执行父类的构造函数再执行子类的构造函数。在对子类函数进行初始化时父类的构造函数也会运行,是因为子类的构造函数默认第一行有一条隐式语句,super(); super会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是:super();
为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取,所以子类对象在建立时需要先查看父类是如何对这些数据初始化的。所以子类在对象初始化时,要先访问以下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
super语句一定要定义在子类的构造函数的第一行。
子类的所有构造函数,默认都会访问父类中空参数的构造函数。因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定要访问的构造函数。
当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数访问到父类中的构造函数。
没有条件的递归就是死循环。
覆盖:1.子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。2.静态只能覆盖静态。
重写:子类和父类方法一模一样。
重载:只看同名函数的参数列表。
12.Java的编译方式
Java有两种编译方式:(1)直接把源代码编译成和本地机器平台相关的机器语言,叫 即时编译;(2)把源文件编译成一种中间的字节码与机器平台无关叫 解释型
13.匿名对象
匿名对象使用方式一:当对象的方法只调用一次时可以用匿名对象来完成。这样写比较简化如果对一个对象进行对个成员调用必须给这个对象起名字,匿名内部类调用成员变量无任何意义。
匿名对象使用方式二:可以将匿名对象作为实际参数进行传递。
14.泛型
泛型是JDK1.5出现的新特性,用于解决安全问题是一个类型安全机制。
好处:1.将运行时期出现的ClassCastException问题转移到编译时期,方便程序员解决问题,让运行时期问题减少,安全。2.避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。 
泛型应用场合:通常在集合框架中很常见,只要见到<>就要定义泛型 ,其实<>就是用来接收类型的。当使用集合时,集合中要存储的数据类型作为参数传递到<>即可。
什么时候定义泛型类?当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展。
泛型类:
泛型可以定在类上也可以定义在方法上。
泛型类定义的泛型在整个类中有效,如果被方法使用,那么泛型类明确要操作的具体类型后,所有要要操作的类型都已经确定了。为了让不同方法可以操作 不同类型而且类型不确定,那么可以将泛型定义在方法上。
泛型方法:
特殊之处:静态方法不可以访问类上定义的泛型。如果静态方法操作的应用数据类型不确定可以将泛型定义在方法上。
静态泛型方法:

泛型定义在接口上:
<?>表示引用数据类型不明确,?通配符
泛型限定:<? extends E>可以接受E类型或者E的子类,上限。
                <? super E>可以接受E类型或者E的父类
15.String类
字符串是一个特殊的对象一旦被初始化就不能改变。
public final  class String
equals方法比较内存地址值。
常见字符串操作:
1.获取
     1.1字符串中包含的字符数也就是字符串的长度。
          int length():获取长度
     1.2根据位置获取位置上的某个字符
          char chartAt(int index):
      1.3根据字符获取该字符在字符串中的位置
          int indexOf(int ch):返回的是在字符串中第一次出现的位置
          int indexOf(int ch,int indexFrom):从fromIndex指定位置开始获取字符ch在 字符串中出现的位置。
          int indexOf(String  str):返回的是str在字符串中第一次出现的位置
          int indexOf(String str,int indexFrom):从fromIndex指定位置开始获取str在 字符串中出现的位置。
           int  lastIndexOf(String  str):返回的是str在字符串中最后一次出现的位置
2.判断
     2.1字符串中是否包含指定字串
          boolean contains()
          特殊之处:indexOf(String str)返回str在字符串中第一次出现的位置,若果返回-1则表示该字符串中不包含stry因此也可以用来判断字符串是否包含某个字串。
     2.2 字符串中是否有内容
          boolean isEmpity():判断字符串长度是否为0.
     2.3 字符串中是否以指定内容开头
          boolean startsWith(String prefix)
     2.4字符串是否以指定内容结尾
          boolean endsWith(String str)
     2.5判断字符串的内容是否相同(复写Object类中的equals方法)
          boolean equals(String str)
     2.6判断字符串长度是否相同并忽略大写小
          boolean equalsIgnoreCase()
3.转换
     3.1将字符数组转换为字符串
          构造函数:Strirng(char[] arry)  
                          String(char[] arry,int offset,int count):将字符数组中的一部分转换为字符串
          静态方法:static String copyValueOf(char[] arry)
                               static String copyValueOf(char[] arry,int offset,int count)
                             static String ValueOf(char[] arry)
                                 static String ValueOf(char[] arry,int offset,int count)
     3.2将字符串转换为字符数组
          char[] toCharArray()
     3.3将字节数组转换为字符串      
          Strirng(byte[] arry)  
         String(bytear[] arry,int offset,int count):将字节数组中的一部分转换为字符串
     3.4将字符串转换为字节数组
        byte[] getBytes()
     3.5将基本类型转换为字符串类型
          static String valueOf(int|double|short|char(基本数据类型) data)
特殊:字符串和字节数组在转换过程中是可以指定编码表的。
4.替换
     String replace(char oldChar,char newChar)
     String replace(CharSequence target,CharSequence replacement)
5.切割
     String[] split( regex)
6.子串(获取字符串中的一部分)
     String subString(int beginIndex)
     String subString(intbeginIndex,int endIndex)(包含头不包含尾)
7.转换、去除空格、比较
     7.1将字符串转换为大写或小写
          String toUpperCase()
          String toLowerCase()
     7.2将字符串两端多余空格去除
          String trim()
     7.3对两个字符串进行自然顺序的比较
          int compareTo(String anotherString)
 StringBuffer是一个容器它可以对字符串进行增删,StringBuffer是长度是可变的。
public final class StringBuffer 
StringBuffer特点:1.长度可变。2.可以一次操作多个数据类型。3.通过toString方法转化为字符串
1.存储
     StringBuffer append():将指定数据作为参数添加到已有数据尾处。
     StringBuffer insert(index,data):在指定位置处插入数据。
2.删除
     StringBuffer delete(start,end):删除缓冲区中的数据包含start,但不包含end。
     StringBuffer  deleteCharAt(index):删除指定位置的字符。
3.获取
     StringBuffer charAt(index)
     int indexOf()  
      int lastIndexOf()
      String subString(start,end)
4.修改 
     replace(int start,int end.String str)
     void setCharAt(int index,char ch)
5.翻转
     StringBuffer reverse()
6.void getChars(int srcBigin,int srcEnd,char[] dest,int dstBegin)将缓冲区中的指定字符保存到字符数组。
StringBuilder:StringBuffer的简易替换,不保证线程安全。
JDK1.5出现StringBuilder,与StringBuffer的区别是:StringBuffer是线程同步的,StringBuilder是线程不同步的。
升级三个因素:1.提高效率 2.简化书写 3.提高安全性
16.Jar包
好处:1.方便与项目的携带。2.方便使用,只要在classpath中设置jar路径即可。3.数据库驱动,SSH框架等都是以jar包体现。
jar包的使用:

17.异常
异常:程序在运行时出现的不正常情况。
异常的由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。其实就是java对不正常情况进行描述后的对象体现。 
对于问题的划分:两种:一种是严重的的问题;一种是非严重的问题。对于严重的java通过Error类进行描述。对于非严重的java通过Exception进行描述。
对于Error一般不编写针对性的代码对其进行描述。对于Exception可以使用针对性的处理方式进行处理。
Throwable(直接子类:Error类  Exception类)
java异常处理的机制:
try{
     被检查代码块
}catch(异常类  变量){
   处理异常的代码(处理方式)
}finally{
     一定被执行的语句
}

对捕获到的异常对象常见方法操作:1.String  getMessage()  2.String toString()   3.void printStackTrace()   jvm默认的异常处理机制就是在调用printStackTrace()方法,打印异常在堆栈中的跟踪信息。
在函数上声明异常,便于提高安全性让调用者进行处理,不处理编译失败。
对多异常的的处理:1.声明异常时建议声明为更具体的异常。这样处理的可以更具体。2.声明几个异常就对应几个catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
建议在进行异常处理时,catch中一定要定义具体处理方式。
当在函数内部出现throw抛出异常对象,那么就必须给出处理动作。要么在内部try-catch处理要么在函数上声明让调用者处理。
一般情况在函数内出现异常,函数上需要声明。
自定义异常:必须是自定义类继承Exception。
继承Exception的原因:异常体系有一个特点,因为异常类和异常对象都被抛出。他们都具有可抛性,这个可抛性是Throwable这个体系独有的特点。只有这个体系中的类和对象才可以被throws和throw操作。
throws 和throw的区别:1.throws使用在函数上;throw使用在函数内。2.throws后面跟的是异常类可以跟多个用逗号隔开;throw后面跟的是异常对象。
Exception中有一个特殊的子类异常RunTimeException运行时异常。如果在函数内抛出该异常可以不用声明编译一样通过。如果在函数上声明了该异常,调用者可以不用进行处理。编译一样通过。 
 之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生希望程序停止,因为在运行时出现无法继续运算的情况,希望停止后对代码进行修正。常见的RunTimeException异常:Arithmetic Exception、ClassCastExcepton、NullPointerException、IndexOutOfBoundsException、IllegalArgumentException等。
自定义异常时如果该异常的发生无法再继续进行运算就让自定义异常类继承RunTimeException。
对于异常分两种:1.编译时被检测的异常。2.编译时不被检测的异常(RunTimeException及其子类)
finally一定被执行的代码。finally代码块定义一定执行的代码,通常用于关闭资源。因为资源必须要释放。  
异常处理格式:格式1.try{}catch(){}。格式2.try{}catch(){}finally()。格式三:try{}finally{}。
记住:catch是用来处理异常的,如果没有catch就代表异常没被处理过,那么必须声明。
异常在父类覆盖中的体现:1.子类在覆盖父类时如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。2.如果父类方法抛出多个异常,那么子类在覆盖该方法时只能抛出父类异常的子集。
3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不能抛出异常。如果子类方法发生异常就必须要进行try处理,不能抛。
finally只有一种情况读不到:就是在finally语句前存在System.exit(0);系统退出,jvm结束。
或者异常可以处理,但需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理,也可以将捕获异常处理后转换成新的异常。



18.object类
object类是所有类的直接或间接父类。
该类中定义的是所有对象都具备的功能。
19.多态
多态:可以理解为事物存在的多种体现形态。
1.多态的体现:父类的引用指向了自己的子类对象。父类的引用也可以接受自己的子类对象。
2.多态的前提:必须类与类之间有关系,要么继承要么实现。通常还有一个前提,存在覆盖。
3.多态的好处:多态的出现大大提高了程序的可扩展性。
4.多态的弊端:只能使用父类的引用访问父类中的成员。
类型提升:向上转型。
强制将父类的引用转换为子类类型:向下转型。
class Fu{
     ......
     }
class Son extends Fu{
     ...........
}
class Cast{
     public static void main(String[] args)
     {
               Fu fu=new Son();              //向上转型,类型提升
               Son son=(Son) fu;          //向下转型,强制将父类的引用,转换成子类类型。
    }
}
20.集合类
集合类:面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象进行操作,就对对象进行存储,集合就是存储对象最基本的一种方式。
数组和集合的区别:数组虽然也可以存储对象但长度是固定的,集合是可变的。数组中可以存储基本数据类型但集合只能存储对象。
集合类的特点:集合只用于存储对象,长度可变,结合可以存储不同类型的对象。 
为什么会有那么多容器?因为每个容器对数据的存储方式不同。这个存储方式称为数据结构。
add方法的参数类型是Object以便接受任何类型
集合中存储的都是对象的引用。 
Collections中包含了一些操作集合对象的方法,具体方法请参考:  http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
public interface iterator<E>:方法:hasNext()  next()  remove()
迭代器就是集合取出元素的方式。
List元素是有序的,元素可以重复,因为该集合体系中有索引。
Set元素是无序的,元素不可以重复。 
List特有方法:凡是可以操作角标的方法都是List特有方法。
     增
          add(index,element)
          add(index,Collection)
     删
          remove(index)
     查
          get(index)
          subList(from,to)
          listIterator()
     改
          set(index,element)
List集合特有的迭代器ListIterator是Iterator的子接口,该接口只能通过List集合的listLiterator方法获取。ListIterator可以在遍历过程中进行增删查改。
ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快但是增删稍慢。线程不同步。初始容量为10,增速为1.5倍。
LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。
Vector:底层是数组数据结构。线程同步。初始容量为10,增速为2倍。
Enumeration是Vector特有的取出方式。其实枚举和迭代是一样的.
LinkedList特有方法:
addFirst()    addLast()     
获取元素不删除元素 如果集合中没有元素会出现NoSuchElementException :getFirst()   getLast()            
获取元素删除元素如果集合中没有元素会出现NoSuchElementException:removeFirst()   removeLast()  
JDK1.6版本出现的替代方法:offerFirst()    offerLast()     
获取元素不删除元素 如果集合中没有元素 会返回nul :peekFirts()   peekLast()    
获取元素删除元素 如果集合中没有元素会返回null :pollFirst()   pollLast()
堆栈:先进后出
队列:先进先出
在迭代时循环中next调用一次,就好hasNext判断一次。
Object类中的equals方法比较的是内存。
List集合判断元素是否相同依据的是equals方法。
set:元素是无序(存入或取出的顺序不一定一致。) 元素不可以重复。
set集合的功能和collection是一致的。
hashSet底层数据结构是哈希表。 (哈希表存放一堆哈希值的表,先判断哈西值是否一样,如果一样再判断是否为同一对象),线程是非同步的。
hashSet保证元素唯一性的原理:通过元素的两个方法hashCode和equals方法来完成,如果元素的hashCode的值相同才会判断equals是否为true,如果元素的hashcode不同不会调用equals方法。
对于判断元素是否存在以及删除等操作依赖的时hashCode和equals方法。
TreeSet可以对Set集合中的元素进行排序。DI底层数据结构是二叉树,保证数据唯一性的依据是compareT方法return 0。
实现比较的接口:public interface Compare<T> 此接口强行对实现它的每个类的对象进行整体排序,这种排序被称为类的自然排序。
方法:int CompareTo(T o)返回负整数、零、正整数,根据此对象对象是大于、等于、还是小于指定对象。
排序时当主要条件相同时一定要判断一下次要条件。
TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Compare接口,覆盖compareTo方法
TreeSet排序的第二种方式:当元素自身不具备比较性,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。在集合初始化时就有了比较方式。TreeSet(Comparator <? super E> comparator)实现Comparator接口覆盖compare方法(int compare(Object obj1,Object obj2))
当两种比较都存在时,以比较器为主。定义一个类实现comparator接口覆盖compare方法。
21.基本类型封装类
基本数据类型与包装类型对应关系:1.short     Short   2.byte   Byte  3.int     Integer   4.char  Character  5.boolean  Boolean  6.long   Long  7.float  Float    8.double    Double
基本数据类型对象包装类最常见的作用就是:用于基本数据类型和字符串之间转换。
基本数据类型转字符串:基本数据类型+“”  基本数据类型.toString(基本数据类型值)
字符串转基本数据类型: static parseInt(字符串 )
十进制转其它进制: Integer.toBinaryString(int data)     Integer.toHexString(int data) 
                              Integer.toOctalString(int data)
其它进制转十进制:parseInt(string,radix)
自动拆箱自动装箱:
class  A
{
     Integer  a=new Integer(4);
     Integer  b=4;   //自动装箱(new Integer(4))
     b=b/* b.intValue */+2;   //b进行自动拆箱变成int型,和2进行运算,然后再将结果自动装箱赋给b。注意null值

     Integer m=128;
     Integer n=128;
     Integer a=127;
     Integer b=127;
    判断   m==n     false
     判断  a==b      true
  原因:a和b指向了同一个对象,当数值在byte范围内时对于新特性如果该数值应经存在不会开辟新空间。
}
22.内部类
内部类定义形式:
class Outer{
     ......
     class Inner{
       .........
     }
}
class InnerClassDemo{
     public static void main(String[] args)
    {
          Outer.Inner in=new Outer().new Inner();   //直接访问内部类中成员。
     }
}
内部类的访问规则:1.内部类可以直接访问外部类的成员,包括私有。之所以可以直接访问是因为内部类中持有了外部类中的一个引用。格式:外部类名.this。2.外部类要访问内部类必须建立的内部类对象。
内部类在成员位置上可以被私有。
访问格式:1.当内部类定义在外部类的成员位置上而且非私有,可以在外部其他类中直接建立内部类对象。格式:外部类名.内部类名 变量名=外部类对象.内部类对象。
2.当内部类在成员位置上时就可以被成员修饰符修饰。如,private:将内部类在外部类中进行封装。staic:内部类就具有static的特性。当内部类被static修饰后,只能直接访问外部类中的静态成员。
在其他外部类中访问static内部类的非静态成员:new Outer.Inner().function()。
在其他外部类中访问static内部类的静态成员:new Outer.Inner.function()。
注意:当内部类中定义了静态成员该内部类必须是static的。当外部类中的静态方法访问内部类时,内部类也必须是static的。
当描述事物时,事物的内部还有事物用内部类来描述。
局部内部类是不能定义静态成员的。局部内部类不能有修饰符。
非静态没对象不运行。
class outer{
     ......
     void function()
    {
          class Inner{
            .......
          }
              new Inner().内部类成员;
     }
}
内部类被定义在局部时:1.不可以被成员修饰符修饰。2.可以直接访问外部类中的成员,因为还持有外部类中的个引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

匿名内部类:1.匿名内部类其实就是内部类的简写形式。2.定义匿名内部类的前提:内部类必须是继承一个类或者实现一个接口。3.匿名内部类的格式:new 父类或者接口(){  定义子类的内容 } 4.其实匿名内部类就是一个匿名子类的对象。
匿名对象的方法只能调用一次。
23.package包
包的作用:1.对文件进行分类管理。2.给类提供多层命名空间。3.写在程序的第一行。4.类名的全称是 包名.类名。5.包也是一种封装形式。
包名所有字母小写。
总结:1.包与包之间进行访问,被访问的包中的类及类中的成员需要public修饰。2.不同包中的子类还可以直接访问父类中被protected修饰的成员。3.包与包之间可以直接使用的权限只有两种:public和protected。
访问权限:
                          public    protecte      default     private
同一个类中          ok             ok              ok             ok
同一个包中           ok            ok              ok
子类                     ok            ok
不同包中              ok
为了简化类名的书写,使用关键字import导入包。
import导入的是包中的类。
开发中建议不要使用通配符,需要用到包中的哪个类就导入哪个类。
建议建立包名不要重复,可以使用url完成定义,url是唯一的。
24.Map
pubilc interface Map<K,V>将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。
collection是单列集合,,map是双列集合。
1.增加
     put(K key, V value)添加元素时如果出现相同的键,那么后添加的值会覆盖原有键对应的值。并put方法会返回被覆盖的值。     
     putAll(Map<? extends K,? extends  V> m)
2.删除
     clear()
     remove(Object key)
3.判断
     containsKey(Object obj) containsValue(Object obj)
4.获取
     get(Object key)(返回对应的值)
     size()
     values():获取Map中所有的值。 
     entrySet()
     keySet()
map:
--HashTable:public class HashTable<K,V> extends Dictionary<K,V> implements Map<K,V>。
                    底层是Hash表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0 效率低
--HashMap:底层是Hash表数据结构,允许使用null键 null值,该集合是不同步的。jdk1.2 效率高
--TreeMap:底层二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序。
Map集合的两种取出方式:1.set<k> keySet将Map中所有的键存入到set集合,因为set具有迭代器,所以可以通过迭代方式取出所有键,再根据get方法获取每一个键对应的值。
Map集合的取出原理:将Map集合转变为Set集合,再通过迭代器取出。
2.Set<Map.Entry<k,v>> entrySet():将Map集合的映射关系存入到了集合中,而这个关系的数据类型就是:Map.Entry。
Map.Entry其实Entry也是一个接口,它是Map接口中的一个内部接口。
interface Map{
     public static interface Entry{
          public abstract Object getKey(){}
          public abstract Object getValue(){}
     }
}
Map集合使用场合:当数据之间存在映射关系时,可以选择Map集合。
Map扩展知识:Map集合被使用是因为具备映射关系。
25.多线程
进程:是一个正在执行中的程序。每一个进程执行都有执行顺序,该顺序是一个执行路径或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程控制着进程的执行。
一个进程中至少有一个线程。 
Java vm启动的时候会有一个进程java.exe。而且该线程的运行代码存在于main方法中。该线程成为主线程。
其实JVM启动时不止一个线程还有垃圾回收机制的线程。
启动线程的第一种方式:继承thread类。
步骤:1.定义类继承Thread.2.重写Thread类中的run方法(目的:将自定义代码存储在run方法中,让线程运行)。3.创建对象调用线程的start方法。(start方法有两个作用:1.启动线程。2.调用run方法。)
每次运行结果都不同?因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。
明确:在某个时刻只能有一个程序在运行(多核除外)。cpu在做着快速的切换以达到看上去是在同时运行的效果。
可以把多线程的运行形容为互相抢夺CPU执行权。这是多线程的一个特性:随机性。谁抢到谁执行,执行时间长短由cpu决定。
为什么要覆盖run方法?Thread类用于描述线程,该类就定义了一个功能用于存储线程要运行的代码,该存储功能就是run方法。也就是说Thread类中的run方法用于存储线程要运行的代码。
线程的运行状态:
static Thread currentThread:获取当前正在执行的线程。
getName:获取线程名称。
设置线程名称:构造函数或setName。
创建线程的第二种方式:实现Runable接口。步骤:1.定义一个类实现Runable接口。2.覆盖Runable接口中的run方法(将线程要运行的代码存放在run方法中)。3.通过Thread类建立线程对象。4.将Runable接口的子类对象作为实际参数传递给Thread类的构造函数。(为什么要将Runable接口的子类对象作为实参传递给Thread构造函数?因为自定因run方法所属的对象是Runable接口的子类对象所以要线程执行指定对象的run方法,就必须明确该方法所属对象。)5.调用Thread类的start方法开启线程并调用Runable接口子类的run方法。  
实现方式和继承方式的区别:1.避免了单继承的局限性。2.在定义线程时建议使用实现方式。3.继承Thread:线程代码存放在Thread子类run方法中。实现Runnable:线程代码存在接口的子类run方法中。
Java对于多线程的安全问题提供了同步代码块方式解决。
synchronized(对象){需要被同步的代码} 对象如同锁,持有锁的线程可以在同步中执行,没有获取锁的线程即使获得cpu的执行权也进不去,因为没有获取锁。
同步的前提:1.必须保证有两个或两个以上线程。2.必须是多个线程使用同一个锁。(必须保证同步中只能有一个线程在运行)
好处:解决了多线程安全问题
弊端:多个线程都需要判断锁较为消耗资源。
如何找问题:1.明确哪些代码是多线程运行代码。2.明确共享数据.3.明确多线程运行代码中哪些语句是操作共享数据的。 
同步的两种表现形式:1.同步代码块。2.同步方法。(synchronized 最为修饰符修饰函数)
同步函数用的锁的问题?函数需要被对象调用,那么函数都有一个所属对象引用就是this所以同步函数使用的锁是this.
如果同步函数被静态修饰,那么方法所属对象不是this,因为静态方法中不可以定义this.静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。类名.class 该对象类型是class。
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class 。
死锁:同步中嵌套同步。
线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。
notify()唤醒线程  notifyAll()唤醒所有的线程   wait()等待会释放对象锁。这三个方法都使用在同步中,因为要对持有监视器(锁)的线程进行操作。
为什么操作线程的方法定义在object类中?因为这些方法在操作同步中线程时都必须要表示要操作线程持有的锁,只有同一个锁上被等待的线程,可以被同一个锁上notify唤醒,不可以对不同锁中线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁是可以是任意对象,可以被任意对象调用的方法定义在object类中。
JDK1.5中将同步synchronized替换成实现lock操作,将object中的wait,notify,notifyAll,替换了condition对象,该对象可以lock锁进行获取。
停止线程:1.定义循环结束标记符。(特殊情况:当线程处于冻结状态就不会读取到标记,线程就不会结束)2.使用interrupt方法。(注:stop方法已经过时不再用)
如何结束线程?run方法结束,开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束也就是循环结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行中来。这时就可以操作标记让线程结束。
thread类中提供该方法interrupt().
Thread类中的其他方法:1.public final void setDaemon(boolean on):将线程标记为守护线程或用户线程。
2.public final void join() throws interrupptException 3. public static void yield():暂停正在执行的线程对象并执行其他线程。
当A线程执行到B线程的join方法时,A就会等待等到B线程执行完毕A线程才会执行,join可以用来临时加入线程执行。
26.集合工具类Collections
1.Collections- sort方法:public static <T extends Comparable<? super T>> void sort(List< T>l ist,Comparable<? super T > c )
2.Collections-max方法:public static <T extends Object&Comparable<?super T>>max(Collection<? extends T> coll)
3.Collections-binarySearch:public static <T>int binarySearch(List<? extends Comparable<? super T>> list,T key)
4.Collections-fill:将List集合中所有元素替换成指定元素。static <T> void fill(List<? super T> list,Object obj)
5.Collections-replaceAll:static <T> boolean replaceAll(List<T> list,T oldVal,T new Val)
6.Collections-reverse:static void reverse(List<?> list)
7.Collections-reverseOrder:public static <T> Comparator<T> reverseOrder():返回一个比较器,强行逆转实现了Comaprable接口的对象collection的自然顺序。public static <T> Comparator<T> reverseOrder(Comparator<T> cmp)
8.Collections-SynList:实现集合中对象的线程安全。参考:http://tool.oschina.net/apidocs/apidoc?api=jdk_7u4
9.Collections-swap:static void swap(List<?> list,int i,int j):交换两个元素的位置。
10Collections-shuffle:static void shuffle(List<?> list):使用默认随机源对指定列表进行置换。
27.Arrays工具类
Arrays用来操作数组的工具类,里面都是静态方法。
static int binarySearch(Object[] a,Object key)
static int binarySearch(Object[] a,int fromIndex,int toIndex,Object key)
long、int、short用法同Object。
static int binarySearch(T[] a,T key,Comparator<? extends T> c)
static int binarySearch(T[] a,int fromIndex,int toIndex,T key,Comparator<? extends T> c)
static boolean deepEquals(Object[] a1,Object[] a2)
static<T>List<T> AsList ()(T.....a):把数组转变为List集合.
将数组转变为List集合的好处: 可以运用集合的思想和方法操作数组中的元素。
注意:将数组转变为集合不可以使用集合的增删方法,因为数组的长度是固定的。
如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
更多Arrays提供的方法请参考: http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
28.集合变数组
使用的方法是集合的toArray()方法:1.Object[] toArray() 2.<T>T[] toArray(T[] a)
指定类型的数组长度的定义规则:当指定类型的数组长度小于集合的size,那么该方法会创建一个新的数组,长度为集合的size;当指定类型的数组长度大于集合的size,就不会新创建数组,而是使用传递进来的数组。所以创建一个刚刚好的数组最优。
集合变数组的原因:限定集合对数组的操作。 不需要进行增删。
29.增强for循环
高级for循环:格式:for(数据类型 变量名:被遍历的集合(Collection)或数组 ){}
只能对集合中的元素进行取出,而不能进行修改。
 对集合进行遍历只能获取集合元素,但是不能对集合进行操作。
迭代器除了遍历,还可以进行remove集合中元素的动作。如果是ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
传统for和高级for的区别:高级for有一个局限性,必须有被遍历的目标。
集合可变参数:其实就是一种数组参数的简写形式,不用每次都手动的建立数组对象,只要将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。

可变参数 JDK1.5出现的新特性,方法的可变参数,在使用时注意,一定要将可变参数定义在参数列表的最后面。
30.静态导入

当类名重名时,要指定具体的包;当方法重名时要指明具体所属的对象或类。
31.常用类
System
public final class System extends Object,该类不能被实例化。
System类中的方法和属性都是静态的。
static printStream err:标准错误输出流。
static  inputSream in:标准输入流。
static printStream out:标准输出流。
方法:1.static long currentTimeMilis()  2.static void gc()   3.static void exit(int status)
4.static properties getProperties()  5.static String setProperty(String key,String value)
6.static String getProperity(String key)
--------------------------------------------------------------------------------------------
Runtime
public class Runtime extends Object,每一个java应用程序都有一个Runtime实例,使应用程序能够与其运行的环境相连接。没有构造函数,不能new对象。
static Runtime getRuntime()
方法:1.process exec(String command)   2.void gc()
public abstract class Process  extends Object
方法:abstract destroy(){}

--------------------------------------------------------------------------------------------
Date:public class Date extends Object implements Serializable,Cloneable,Comparable<Date>
构造方法:1.Date() 2.Date(long date)
DateFormate:public abstract class DateFormate extends Format
方法:1.String formate(Date date) 2.
DateFormat的实现类是simpleDateFormat
public class SimpleDateFormat extends DateFormat
构造方法:1.SimpleDateFormat() 2.SimpleDateFormat(String pattern) 3.SimpleDateFormat(String pattern,Locale locale)

----------------------------------
Calendar:public abstract class Calendar   extends Object implements Serializable,Cloneable,Comparable<  Calendar>
构造方法:1.protected Calendar() 2.protected Calendar(TimeZone zone,Locale locale)
三种更改日历字段的方法:1.set(f,value) 2.add(f,delta)   3.roll(f,delta)
------------------------------------------------------------------------------
Math类:public final class Math extends Object
方法:1.static double ceil(double a):  返回大于指定数据的最小整数。 
      2.static double floor(double a) :返回小于指定数据的最大整数。
           3.static int round(float f):四舍五入。
            4.static double pow(double a,double b)
            5.public static double random():返回大于等于0.0小于1.的随机数
随机数的产生也可以用java。util包中的Random类产生。
------------------------------------------------------------------------------------
32.装饰设计模式
当想要对已有的对象进行功能增强时,可以自定义类将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类成为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,
class      Decorate
{
        public void function()
        {
              功能代码
        }
}
class SuperDemorate
{
      private Decorate decorate;
      public SuperDemorate( Decorate    decorate)
      {
                this.decorate=decorate;
        }
        public void superFunction()
        {
                decorate.function();
                其他增强功能代码。
        }
}

装饰模式与继承的比较:装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系,装饰类因为增强了已有对象,具备的功能和已有的是相同的。只不过提供了更强功能,所以装饰类和被装饰类通常是都属于一个体系的。(装饰类和被装饰类同属于一个父类或接口)
33.IO流
1.IO流用来处理设备之间的数据传输
2.Java对数据的操作是通过流的方式
3.Java用于操作流的对象都在IO包中
4.流按操作数据分两种:字节流与字符流;按流向分为:输入流,输出流。
字节流的抽象基类:InputStream OutputStream
字节流的抽象基类:Reader  Writer
-------------------------------------
IO流--字符流:

FileWriter:
构造方法:1.FileWriter(File file)  2. FileWriter(File file,boolean append)                 
                  3.   FileWriter(FileDescriptor   fd)   4.  FileWriter(String fileName):创建一个新文件,如果存在就覆盖以前的文件。    4.   FileWriter(String fileName,boolean append):传递一个true参数代表不覆盖已有的文件,并在已有的数据末尾进行数据续写。
方法:1.write()   2.flush()   3.close()
IO异常处理格式以FileWriter为例:
class ExceptionDeal{
    FileWriter fw=null;
    try{
           fw=new FileWriter("filepath");
            fw.writer("content");
    }
    catch(IOException e)
    {
            e.printStackTrace();
    }
    finally
    {
        try{
                if(!fw==null)
                    {
                        f.close();
                    }
            catch(IOException e)
            {
                    ......................
               }
        }
    }
}
------------------------------------------------------
FileReader:构造方法:1.  FileReader(File file)   2. FileReader(FileDescriptor fd)     
                                        3.FileReader(String fileName)
方法:1.int read()方法一次读一个字符,而且自动往下读。当读到结尾,返回-1.
            2.int read(char cbuf)
            3.int read(char cbuf,int off,int len)
-----------------------------------------------
字符流的缓冲区:缓冲区提高了对数据的读写效率。
缓冲区对应的类:BufferedWriter()   BufferedReader()
缓冲区要结合流才能使用,在流的基础上对流的功能进行了增强。 在创建缓冲区之前,必须要先有流对象。
BUfferedWriter构造方法:1.BufferedWriter(Writer out)  2.BufferedWriter(Writer  out,int  sz)

BufferedWriter提供了一个跨平台的换行符,newLine().
BufferedReader构造方法:1. BufferedReader(Reader in) 2.BufferedReader(Reader in,int sz)
字符读取缓冲区提供了一次读取一行的方法readLine,f方便于对文本数据的获取。当返回null时表示读取到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符。
readLine方法的原理:无论是读一行,还是获取读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read一次读一个的方法。
LineNumberReader:是BufferedReader的直接子类,跟踪行号的缓冲字符输入流。
void setLineNumber(int  lineNumber)  :设置当前行号。
int getLineNumber():获取当前行号。
String readLine():读取文本行。
--------------------------------------------------------------------------------
IO流--字节流:
OutputStream:字符输出流
构造方法:OutputStream()
方法:1.void  close()  2.void flush()  3.void write(char [] b)  4.void writer(char[] b,int off,int len)
           5.abstract void write(int b)
FileOutputStream:往文件中写
FileInputStream:从文件中读。
BufferedInputStream:
BufferedOutputStream:
 读取键盘录入:
System.out:对应的是标准输出设备,控制台。
System.in:对应的标准输入设备,键盘。
InputStreamReader:字节流通向字符流的桥梁。
构造方法:1.InputStreamReader(InputStream in) 
                 2.InputStreamReader(InputStream in,Charset cs)  
                 3. InputStreamReader(InputStream in,CharsetDeoder dec) 
                  3. InputStreamReader(InputStream in,String charsetName) 
OutputStreamWriter:字符通向字节的桥梁。
键盘录入常见写法:BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in))
键盘输出常见写法:BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out))
流操作基本规律:1.明确源和目的:源:输入流:InputStream  Reader 
                                                       目的:输出流:OutputStream  Writer
                            2.操作的数据是否纯文本:是:字符流   否:字节流
                            3.当体系明确后,再明确要使用哪个具体对象
                                通过设备来进行区分:源设备:内存  硬盘    键盘
                                                                    目的设备:内存、硬盘、控制台
转换流可以按照指定的编码表存储数据。转换流是字符流和字节流之间的桥梁,通常涉及到字符编码转码时需要用到转换流。
static void setIn():重新分配标准输出流    static void setOut():重新分配标准输入流。
log4j可以用来建立日志文件。
34.File类
File作用:将文件或文件夹封装成一个对象。方便对文件与文件夹进行操作,File对象可以作为参数传递给 流的构造函数。
File构造方法:1.File(File parent,String child)  2.File(String pathname) 
                        3.File(String parent,String child)  4.File(URI uri)
separator实现跨平台的分隔符。
File类常见操作方法:
1.创建:boolean CreateNewFile()在指定位置创建文件,若文件已经存在,则不创建返回false,和输出流不一样,输出流对象一建立创建文件,如果文件存在,会覆盖。
boolean createTempFile(String prefix,String suffix)
boolean createTempFile(String prefix,String suffix,File directory)
boolean mkdir():创建目录只能创建一级目录。
boolean mkdirs():可以创建多级目录。
2.删除
boolean delete() 删除失败返回假。         void deleteOnExit():在程序退出时删除指定文件。
3.判断
boolean canExecute()
boolean  canRead()
boolean canWrite()
boolean exists()
boolean isDirectory()
boolean  isFile()
isHidden
isAbsolute()
当判断文件对象是否是文件或目录时,必须要先判断该文件封装的内容是否存在,通过exisits判断。
4.获取信息
 getName()
getPath()
getParent():返回的是绝对路径中的父目录。如果获取的是相对路径返回空。如果相对路径中有上一层目录,那么该目录就是返回结果。
getAbsolutePath()
getAbsoluteFile()
long lastModified()
boolean renameTo(File dest)
length()
static File[] listRoots()列出可用的文件系统根。
String[] list():调用list方法的file对象必须是封装了一个目录,该目录还必须存在。
String[] list(FilenameFilter filter):FilenameFilter接口只有一个方法:boolean accept(File dir,String name)
File[] listFiles():
File[] listFiles(FilleFilter filter):
递归注意:1.限定递归的条件  2.限制递归的次数,避免内存溢出。
删除一个带内容的目录,删除原理:在windows中删除目录是从里面往外删除的
35.Properties简述
Properties是Hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串。是集合中和IO容器相结合的集合容器。该集合的特点:可以用于键值对形式的配置文件。
Properties是线程安全的,多个线程可以共享单个Properties对象而无需进行外部同步。
构造方法:1.Properties()  2.Properties(Propoerties defaults)
方法:1.String getProperties(String key):获取指定键的值
            2.void list(PrintStream out)  void list(PrintWriter out) 
            3.void load(InputStream is)   void load(Reader reader) 
            4.Object setProperties(String key,String value)
            5.Set<String> stringPropertyNames()

36.IO中的其他类
1.打印流:printWriter  printStream
    打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
    字节打印流:PrintStream 构造函数可以接收的参数类型:1.File对象:File   2.字符串路径:String  3.字节输出流:OutputStream
    字符打印流:PrintWriter构造函数可以接收的参数类型:1.File对象:File   2.字符串路径:String  3.字节输出流:OutputStream 
                                                                                            4.字符输出流:Writer
2.序列流:SequenceinputStream对多个流进行合并。其他输入流的逻辑串联。构造方法:1.SequenceInputStream(InputStream s1,InputStream s2)       2.SequenceInputStream(Enumration<? extends InputStream> e)
3.操作对象:ObjectInputStream ObjectOutputStream,被操作的对象需要实现Serializable(标记接口)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值