JAVA基础

来源:互联网 发布:小型局域网网络搭建 编辑:程序博客网 时间:2024/05/29 17:00

基本数据类型

在Java中,只有基本类型不是对象(数值,字符,布尔类型).
所有的数组类型都是对象,拓展于Object类.

类型 大小 取值范围 int 4字节 -2^32~2^32-1 short 2字节 -2^16~2^16-1 long 8字节 -2^64~2^64-1 byte 1字节 -2^8~2^8-1 float 4字节 正负3.40282347E+38F(有效位6~7位) double 8字节 正负1.7976313486231570E+308(有效位15位)

数据形式约定

  • 长整型数值有一个后缀L(如4000000000L).
  • 十六进制数值有前缀0x,八进制前缀为0.
  • float类型的数值有一个后缀F(如3.402F),没有后缀F的浮点数默认为double类型.double类型数值后缀为D.

对象包装器与自动打包

所有基本类型都有一个与之对应的类,这些类称为包装器.
Integer,Long,Float,Double,Short,Byte,Character,Void,Boolean.对象包装器是不可变的,即一旦构造了包装器就不允许改变包装在其中的值.

    ArrayList<Integer> list=new ArrayList<Integer>();//数组列表尖括号中的类型参数不允许是基本类型    list.add(3);//自动变换成list.add(new Integer(3));这种变换称为自动打包.    int n=list.get(0);//自动变换成int n=list.get(0).intValue();称为自动拆包



枚举类型

   enum Size{SMALL,MEDIUM,LARGE};   Size s=Size.SMALL;



字符串

  • int compareTo(String other) 按照字典排序,如果字符串位于other之前,返回负数;如果位于之后返回正数;相等返回0.
  • boolean equals(Object other) 如果字符串与other相等返回true.
  • int indexOf(String str) 返回与str匹配的第一个子串的开始位置;若不存在,返回-1.
  • String substring(int begin)
  • String substring(int begin,int end) 返回字符串中从begin到串尾或end-1的子串
  • String replace(String old,String new) 将new替换掉字符串中所有的old.
  • String trim() 去除字符串头部和尾部的空格

构建字符串

    StringBuilder builder=new StringBuilder();    builder.append('a');    builder.append('b');    builder.append("cdef");    String completeString=builder.toString();



输入输出

控制台输入输出

    Scanner in=new Scanner(System.in);    System.out.print("What is your name?");    String name=in.nextLine();

文件输入输出

    Scanner in=new Scanner(new File("infile.txt"));    String s=in.nextLine();    PrintWriter out=new PrintWriter("outfile.txt");    out.printf("%s",s);

输入函数

String nextLine() 读取下一行
String next() 读取下一个单词(以空格作为分隔符)
int nextInt()
double nextDouble()
boolean hasNext() 检测是否还有其他单词
boolean hasNextInt()
boolean hasNextDouble()




数组

For each循环

for(variable : collection) statement collection这一集合表达式必须是一个数组或者实现了Iterable接口的类对象.

数组拷贝

在JAVA中,允许将一个数组变量拷贝给另一个数组变量,这时两个变量将引用同一个数组

    int[] newNums=oldNums;    newNums[5]=12;//oldNums[5]也将变成12

将一个数组的所有值拷贝到另一个新的数组中可避免上面的问题

    int[] newNumbers=Arrays.copyOf(oldNumbers,oldNumbers.length); //如果新老数组是同一个数组则可通过这个方法增大数组大小

数组排序

Arrays类中的sort方法承诺可以对对象数组排序,但要求满足下列前提:对象所属的类必须实现了Comparable接口

    int[] a=new int[100];    ....    Arrays.sort(a);

数组赋初始值

static void fill(type[] a,type value) 将数组所有元素值设为value.

数组equals

static Boolean equals(type[] a,type[b])
如果两个数组长度且元素完全一样则返回true.数组类型可以是:Object;int,long,short,char,byte,boolean,float,double.

泛型数组

ArrayList是保存对象类型元素的泛型类

boolean add(T obj) 数组列表尾端添加一个元素。永远返回true.
int size() 返回实际存储的元素个数
void trimToSize() 去除列表多余的空间
void set(int index,T obj) 设置第index个元素
T get(int index) 返回第index个元素
void add(int index,T obj) 在index+1的位置上插入元素
T remove(int index) 删除并返回第index个元素



产生随机数

    Random generator=new Random();    int x=generator.nextInt(1000);//返回0~999之间的随机数



对象与类

  • 如果将一个方法应用于一个值为null的对象上会产生运行错误.
  • 变量不会自动地初始化为null,必须通过调用new或显式的设置为null.
  • 文件名必须与public类的名字一样.在一个源文件中只有一个public类,可以有任意个非public类.,非public类的访问权限为默认—-包可见.

方法参数

值调用表示方法接受的是调用者提供的值;引用调用表示方法接受的是调用者提供的变量地址. Java总是采用值调用.

  • 一个方法不能修改一个基本数据类型的参数(数值型和布尔型)
  • 一个方法可以改变一个对象参数的状态
  • 一个方法不能实现让对象参数引用一个新的对象

访问权限

概略
1. 仅对本类可见—-private
2. 对所有类可见—-public
3. 对本包和所有子类可见—-protected
4. 对本包可见—-默认

详细

作用范围 当前类 同一个包 其他包 同包子孙类 不同包子孙类 public yes yes yes yes yes protected yes yes no yes yes default yes yes no yes no private yes no no no no

继承

不同于C++,Java不支持多继承

  • 使用super调用构造器的语句必须是子类构造器的第一条语句;如果子类的构造器没有显式的调用超类的构造器,则自动调用超类默认的构造器(即没有参数的构造器),如果超类不存在无参数构造器则出错.
  • 不允许继承的类称为final类
    final class Manager extends Employee    {        ...    }

     类中的方法也可以声明为final,子类就不能覆盖这个方法

    class Employee    {        ...        public final String getName()        {            return name;        }           ...    }
  • 将子类的引用赋给一个超类变量是允许的;将超类的引用赋给子类变量需要进行类型转换. 在超类转换成子类之前应该使用instanceof进行检查.
    if(staff[1] instanceof Manager)    {        boss=(Manager) staff[1];        ...    }

抽象类

包含一个或多个抽象方法的类本身必须被声明为抽象类。
除了抽象方法之外,抽象类还可以包含具体数据和具体方法

  • 类即使不含抽象方法,但可以声明为abstract类
  • abstract不能被实例化
abstract class Person{    ...    public Person(String n)    {        name=n;    }    public abstract String getDescription();    private String name;}

相等测试与继承

instanceof 子类对象instanceof父类为true
Object类中的equals方法用于检测两个对象是否具有相同的引用

    //A是超类,B是子类    Object a=new A();    Object b=new B();    a instanceof A //true    a instanceof B //false    b instanceof A //true  <----------    b instanceof B //true    a.getClass().equals(A.class) // true      a.getClass().equals(B.class) // false      b.getClass().equals(A.class) // false <----------    b.getClass().equals(B.class) // true  

完美的equals方法

class B extends A{    ...    @Override    public boolean equals(Object otherObject)    {      //检测this与otherObject是否引用同一个对象      if(this==otherObject) return true;      //如果为空      if(otherObject==null) return false;      如果子类拥有自己相等的概念,需要采用getClass检测        {      if(getClass()!=otherObject.getClass()) return false;      B other=(B) otherObject;      return field1=other.field&&field2==other.field2...;      }      如果由超类决定相等的概念,则超类肯定定义了equals方法      使用instanceof检测      {      if(!(otherObject instanceof A)) return false;      return super.equals(otherObject);      }   }   ...}

Object类hashCode,toString方法

  • Object类中的hashCode方法,其值为对象的存储地址.
  • Object类中的toString类用来打印对象的类名和散列码
  • equals与hashCode的定义必须一致:如果x.equals(y)==true,那么x.hashCode()就必须与y.hashCode()具有相同的值。例如,如果用定义的Employee.equals比较雇员ID,那么hashCode方法就需要散列ID,而不是姓名或薪水.

参数数量可变的方法

用户可以定义参数数量可变的方法,并将参数指定为任意类型,甚至是基本类型.

    public double max(double... values)    {        ...        values[i]        ...    }

可以这样调用上面的方法

    double m=max(new double[]{3.1,4.3,5});    //或者使用下面方法,使用了自动打包    double m=max(3.1,4.3,5);



反射

能够分析类能力的程序被称为反射.

Class类

一个Class对象实际表示的是一个类型,而这个类型未必是一种类.
获取Class类对象的三种方法

  • 通过对象获取对应的Class类
    Employee e;    ...    Class cl=e.getClass();
  • 调用静态方法Class.forName(类名)获得类名对应的Class类
    String className="java.util.Date";    Class cl=Class.forName(className);
  • 如果T是任意Java类型,T.class就是T对应的Class类型
    Class cl1=Date.class;    Class cl2=int.class;

通过Class类可以快速的创建一个类的实例

    cl.newInstance();//调用默认的构造器,如果不存在会抛出异常

利用反射分析类的能力

Class类中的getFields,getMethods,getConstructors方法将分别返回类的public(和本包的protect)域,方法和构造器,其中包括超类的public成员.
Class类中的getDeclareFields,getDeclareMethods,getDeclareConstructors方法将分别返回类的全部域,方法和构造器,其中包括private和protected成员,但不包括超类的成员.

String modifiers=Modifier.toString(cl.getModifiers());获取修饰符public/private/protect+[static]+[final]

  • 获取所有方法
    Method[] methods=cl.getDeclaredMethods();    for(Method m:methods)    {           String modifiers=Modifier.toString( m.getModifiers());  //获取修饰符        Class reType=m.getReturnType();        String name=reType.getName();//获取方法返回值的类型        //获取方法名        String name=m.getName();        //获取参数        Class[] paramTypes=m.getParameterTypes();        for(int j=0;j<paramTypes.length;++j)        {            System.out.print(paramTypes[j].getName());        }   }
  • 获取所有构造器
    Constructor[] constructors=                     cl.getDeclaredConstructors();    for(Constructor c:constructors)    {           String modifiers=Modifier.toString( c.getModifiers());  //获取修饰符        //获取构造器名        String name=c.getName();        //获取参数        Class[] paramTypes=c.getParameterTypes();        for(int j=0;j<paramTypes.length;++j)        {            System.out.print(paramTypes[j].getName());        }   }
  • 获取所有域
    Field[] fields=                     cl.getDeclaredFields();    for(Field f:fields)    {           String modifiers=Modifier.toString( f.getModifiers());  //获取修饰符        //获取域的类型名        Class type=f.getType();        String typeName=type.getName();        //获取域名        String name=f.getName();        System.out.print(modifiers+" "+typeName+" "+name);   }

在运行时使用反射分析对象

利用反射机制可以查看在编译时还不清楚的对象域.

获取对象域的值

Employee harry=new Employee("Harry Hacker",35000,10,1,1995);Class cl=harry.getClass();Field f=cl.getDeclaredField("name");//通过域名获取指定域Object v=f.get(harry);//获取harry对象的name域的值

当域是私有域,get方法会抛出IllegalAccessException. 为了达到目的,需要调用Field、Method或Constructor对象的setAccessible方法.

Field f=cl.getDeclaredField("name");f.setAccessible(true);Object v=f.get(harry);
  • f.set(obj,value) 将obj对象的f域设置为value.
  • AccessibleObject.setAccessible(fields,true)设置fields数组get权限.

使用反射编写泛型数组代码

bad猜想代码

    void fun()    {        Employee[] a=new Employee[100];        ...        //a 满了        a=(Employee[]) badArrayGrow(a);    }    Object[] badArrayGrow(Object[] a)    {        int newLength=a.length*2;//数组长度增加一倍        Object[] newArray=new Object[newLength];        System.arraycopy(a,0,newArray,0,a.length);        return newArray;    }

   上面的代码有什么问题?

  • 一个一开始就是Object类型的对象是不可以转成Employee对象的.Object[] newArray不能转成Employee[].
  • 即使第一个问题解决了,也不能处理好基本类型数组的拓展。比如执行下面的代码会出问题:
    double[] a=new double[10];    a=(double[]) badArrayGrow(a);

good猜想代码

  • 基于Array.newInstance(componentType,newLength)方法生成新的数组

Core Java(第八版)的代码

    Object goodArrayGrow(Object a)    {        Class cl=a.getClass();        if(!cl.isArray()) return null;        Class componentType=cl.getComponentType();        int newLength=a.length*2;//数组长度增加一倍        Object[] newArray=Array.newInstance( componentType,newLength);        System.arraycopy(a,0,newArray,0,a.length);        return newArray;    }

方法指针(invoke)

从表面上看,Java没有提供方法指针,即将一个方法的存储地址传给另外一个方法,以便第二个方法能够随后调用它. Java提供的接口是一种更好的解决方案,因为接口会使得代码执行速度更快,但Java中方法指针已经作为反射包的副产品出现了.
invoke的参数和返回值必须是Object类型,如果是基本类型,会自动打包拆包.

通过方法名获取方法:

Method m1=Employee.class.getMethod("getName");//获取Employee.class的getName方法

如果需要获取的方法有参数,则还要带入参数:

Method m2=Employee.class.getMethod("raiseSalary",double.class);//获取Employee.class的raiseSalary方法

下面的语句将显示如何调用某个对象的方法:

String n=(String) m1.invoke(harry);//执行harry对象的getName方法m2.invoke(harry,100);//执行harry对象的raiseSalary方法

如果ml方法为静态方法,调用静态方法:

ml.invoke(null [,param]);



接口与内部类

一个类可以实现一个或多个接口,并在需要接口的地方随时使用实现了相应接口的对象.

  • 接口绝不能含有实例域,也不能在接口中实现方法.
  • 接口可以包含常量,接口中的域被自动设为public static final.
  • 接口中所有方法自动地属于public. 在接口中声明方法不必提供关键字public. 在实现接口时必须把方法声明为public. 继承方法的时候应该放宽或者保持访问权限.

可以使用instanceof检测一个对象是否实现了某个接口.if(obj instanceof Comparable) {...};

接口继承

    public interface Powered extends Comparable    {        double fun();    }

实现接口

    class Employee implements Cloneable[,others]    {        ...    }

接口与抽象类?

每个类只能拓展于一个类,却可以实现多个接口.

对象克隆

Java里对象之间等号赋值实现的只是引用,要实现复制一个对象要通过克隆.

  • Object类实现的clone方法只能将数值或者基本类型拷贝,拷贝的子对象其实还是引用的同一个子对象.

Object类的clone方法

clone是Object类的protected方法,用户在编写的代码不能直接调用它,也就是无法直接调用anObject.clone()??—–Core Java第八版

这是我做的测试:
一:

public class A{    public static void main(String... args) throws CloneNotSupportedException     {        new B().clone();  //编译不通过 The method clone() from the type Object is not visible    }}class B{}
  • 编译不通过的原因是,在不同包的子类内部才可以访问超类的protected域和方法.B子类在A子类内部不能访问超类Object的clone方法.

二:

public class A implements Cloneable{    public static void main(String... args) throws CloneNotSupportedException    {        new A().clone();  //运行成功    }}class B{}

总结:其实Core Java(第八版)的这句话说得不合适,它应该这么说:clone是Object类的protected方法,只有在用户编写的Object子类内部才可以调用超类(也就是Object)的protected方法,其他情况不能直接调用它. 即使clone默认的实现能够满足需求,也应该实现Cloneable接口(或者会抛出异常),将clone重定义为public,并调用super.clone().

    class Employee implements Cloneable    {        public Employee clone() throws CloneNotSupportedException        {            Employee cloned=(Employee)super.clone(); //浅拷贝            cloned.hireDay=(Date) hireDay.clone(); //深拷贝            return cloned;        }    }

值得注意的是,Cloneable接口并没有指定clone方法,Cloneable只是作为一个标记,表明类设计者知道要进行克隆处理.

内部类

内部类是定义在另一个类中的类.

类中的类

  • 内部类既可以访问自身的域,也可以访问外围类对象的域.
    public class A    {        private int interval;        public void fun(){/*...;*/}        class B        {            interval=...;        }    }
  • 如果内部类是一个public类,则可以根据任意的外围类对象创建内部类对象.
    public class A    {        /*...;*/        public class B        {        }    }

    对于上面的代码:

    A a = new A();    A.B ab = a.new B();//创建内部类对象,相当于ab的类是A.B
  • 内部类是一种编译器现象,与虚拟机无关. 编译器会把内部类翻译成用$分隔外部类名与内部类名的常规类文件. 可通过反射查看.

  • 只有内部类可以声明为static,在内部类不需要访问外围类对象的时候应该使用静态内部类.

方法中的类

  • 方法中的类(即局部内部类)不能用public,protected,private访问说明符进行声明. 它的作用域被限定在这个方法中,对外部世界完全的隐藏.
  • 若方法中的类用到了方法里的变量,这些变量必须声明为final.
    public class A    {        /*...;*/        public void Afun(int n,final String s) //参数n,s 也属于方法的变量        {            n;            class B            {                //因为内部类里面用到了外部方法的变量,编译器会在内部类生成final String val$s变量,所以外部方法的变量要为final                public void Bfun()                {                    s;                    /*...;*/                }            }        }   }

代理

利用代理可以在运行时创建一个实现了一组给定接口的新类.
这种功能只有在编译时无法确定需要实现哪些接口是才有必要使用.

使用代理的原因:

  • 路由对远程服务器的方法调用(如Hessian).
  • 在程序运行期间,将用户接口事件与动作关联起来.
  • 为调试,跟踪方法调用.

要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法. 这个方法有三个参数.

  • 类加载器,用null表示使用默认的类加载器.
  • Class对象数组,调用处理器构造时的参数对象需要实现的接口.表示的是我给需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了.
  • 调用处理器

调用处理器是实现了InvocationHandler接口的类对象,在这个接口中只有一个方法:Object invoke(Object proxy,Method method,Object[] args).无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用. 实际对象实现实际功能.

下面的代码来自:Ruthless

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;interface HelloWorld {    public void sayHelloWorld();} //类HelloWorldImpl是HelloWorld接口的实现class HelloWorldImpl implements HelloWorld{    public void sayHelloWorld() {        System.out.println("HelloWorld!");    }}class HelloWorldHandler implements InvocationHandler{    //要代理的原始对象     private Object obj;    public HelloWorldHandler(Object obj) {        super();        this.obj = obj;    }    /**     * 在代理实例上处理方法调用并返回结果     *      * @param proxy 代理类     * @param method 被代理的方法     * @param args 该方法的参数数组     */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Object result = null;        //调用之前         doBefore();        //调用原始对象的方法        result=method.invoke(obj, args);        //调用之后        doAfter();        return result;    }    private void doBefore(){        System.out.println("before method invoke");    }    private void doAfter(){        System.out.println("after method invoke");    }}public class HelloWorldTest {    public static void main(String[] args) {        HelloWorld helloWorld=new HelloWorldImpl();        InvocationHandler handler=new HelloWorldHandler(helloWorld);        //创建动态代理对象        HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(                HelloWorldTest.class.getClassLoader(),                 helloWorld.getClass().getInterfaces(),                 handler);        proxy.sayHelloWorld();    }}

运行结果:
结果

0 0
原创粉丝点击