Thinking in java 笔记

初始化与清理

  • 参数的顺序可以区分两个函数
    不能根据返回值来区分两个函数

  • 如果传入的数据类型小于方法中声明的数据类型,实际数据类型就会被提升
    如果无法找到接受char型参数的方法,就会把char直接提升为Int型
    如果传入的实际参数过大,就要强制转化,不然会报错

  • 如果类中没有构造器,编译器会创建一个默认构造函数
    如果定义了,无论是否有参,就不会给你创建,如果你只写了有参的,无参的构造函数就没有了

  • java中的成员函数也像C++中的一样隐含着一个对象参数,但在java中用不上
    常常需要返回自身对象时,或者需要自身对象作为函数参数时,需要用this来代替对象
    this对象可以辅助写多个构造函数(但必须放在开头),可以避免类参数和传入参数产生歧义

  • static方法没有this对象
    static方法中不能调用非stati方法

  • java允许在类中定义一个finalize()函数,一旦垃圾回收器准备少释放对象所占的内存是,将首先调用finalize()方法,java有垃圾回收器,之所以要有此方法是为了针对调用非java程序(例如C程序)时产生的内存泄漏的情况。finalize可以用来当成发现错误的工具(有点类似assert),在程序最终结束时进行终结条件的验证

  • 对于局部变量,如果没有初始化而被使用(即使是基本数据类型)会抛出编译时异常
    但是类中的每个基本类型数据成员都会保证有一个初始值
    注意:无法类中变量自动初始化的运行,它将在构造函数被调用之前发生
    变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,它们仍旧会在任何方法被调用之前得到初始化

  • 只有第一次访问静态数据的时候才会被创建,此后静态对象不会再次被初始化
    初始化的顺序是先静态对象,而后是“非静态”对象
    即使没有显示的static关键字,构造函数实际上也是静态的

  • 数组定义的两种写法:
    int[] a1;int a1[];
    Integer[] a = {new Integer(1),new Integer(2)};这中初始化只能用在定义处

  • 可变参数列表

    Object… args//传参的时候也可以不传,Object也可以变成其他的类型,包括基本类型
    由于可以基本类型和包装类型可以转换(自动装箱),不带参数地或者参数可转化地调用有可变参数的函数,可能会产生歧义(不知道调用哪个,因为每个都可以通过自动装箱或者类型转化匹配上)

访问权限

  • 权限排名:public、protected、包访问权限、private
    protected也提供包访问权限
  • 每个编译单元都只能有一个public类,这个类的名字要和文件名一致,没有public就不作要求
  • 类既不可以是private的也不可以是protected的(内部类除外)
  • 相同目录下所有不明确package声明的文件,都被视为是该目录下的默认包的一部分

复用类

  • 复用包括:组合、继承、代理
  • 初始化变量的四种方式:
    1 在定义对象的地方,也就是定义为类成员的时候(这时候的初始化会在构造函数之前,从侧面也说明了,在构造函数初始化变量的时候,其实变量已经在之前初始化了一次)
    2 在类的构造函数中
    3 在正要使用该变量之前,这也成为惰性初始化
    4 实例初始化(直接赋值)
  • 对于默认构造函数,Java会自动在子类的构造函数中调用基类的构造函数;但是如果构造函数是有参的,就要显式地用super来调用
  • 代理:使用了组合(类中定义了包含了某个对象),但是我们也需要这个对象的方法(成员对象一般是private的不能用),于是就定义与该对象方法同名的方法,然后在方法体中是用这个对象调用同名的方法。为什么不直接用继承呢?这样方法不都有了吗,因为继承关系太近了,所有的方法都方法都暴露给了我们创建的对象。所谓代理,就是我要用你的方法,但是你不想和我有亲缘关系,那就我一旦想做某件事就让你来做,我在旁边看着,而不是我和你一起来做这件事。
  • 子类重新定义的该方法名称并不会屏蔽其在基类中的任何版本,当然签名相同的肯定覆盖了
  • final数据:
    对于非基本类型,final只是保证引用的不变
    final数据可以运行时确定,比如调用random方法产生的数据
    java中可以定义final数据,而不初始化,并且针对不同的对象,初始化为不同的final数据,也称为空白final
  • final参数
    将无法更改参数引用所指向的对象
  • final方法
    可以防止子类修改
    类中所有private方法都是隐式为final方法
  • final类,不能继承

多态

  • 多态的缺陷:
    1 私有方法不能被覆盖,基类的私有方法在子类是不可见,所以多态用不了(重载不了)
    2 某个方法是静态的,其行为就不具有多态性
    3 域访问问题:多态时,直接访问域当然是访问的是基类的(编译时确定的,前提是可访问),但是如果有某个重载的函数,函数里面又访问域,这时访问的是子类的域
  • 构造函数和多态
    在基类的构造函数中,如果没有明确指定调用某个基类构造函数, 他就会默默地调用默认构造函数。如果不存在默认构造函数, 编译器就会报错
  • 构造函数里面调用多态的方法,结果可能是灾难性的,因为,有可能在子类对象还没构造完全,就使用了子类的多态方法
    在构造器内唯一能够安全调用的的那些方法是基类的final方法。这些方法不会覆盖,因袭也不会出现上面的问题
  • 继承和组合的选择规则
    用继承表达行为间的差异,用字段表达状态上的变化

接口

  • 包含抽象方法的是抽象类
    继承自抽象类不去实现抽象方法,将会被强制限定该类为抽象类
  • 接口也可以包含域,但默认都是static和final的,因此可以用来定义常量
  • 接口中的方法即使不写访问权限也是默认为public的
  • 接口中的变量可以被非常量表达式初始化,比如Random类
  • 当实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且,pirvate接口不能在定义它的类之外被实现

内部类

  • 内部类拥有外部类的所有访问权限
  • 内部类有一个指向外部类的引用
  • 使用外部类的引用:outer.this
  • new一个内部类:outer.new inerclass();
  • 拥有外部类之前是不能创建内部类对象的
  • 如果创建的是静态内部类,不需要外部类对象的引用

容器

  • Collection 一个独立的元素序列
    Map 一组成对的键值对对象
  • 如果需要子类的独有方法,定义List或者Map时,就不要使用子类的类型
  • Arrays.asList()可以将一个数组或是一个用逗号分隔的元素列表转换为一个List对象,注意返回的对象大小不能修改,不然会出错(内部是使用了一个数组存储)
    Collection.addAll()比Arrays.asList()用来构造一个Collection要快
  • 构建一个不包含元素的Collection,然后调用Colections.addAll()这种方式很方便。
    //snow是所有类的基类
    List<Snow> snow1 = Arrays.asList(
      new Crusty(), new Slush(), new Powder());

    // 不行,因为Powder才是这两个类最近的基类
    List<Snow> snow2 = Arrays.asList(
    //   new Light(), new Heavy());
    // Compiler says:
    // found   : java.util.List<Powder>
    // required: java.util.List<Snow>

    //可以工作,实际上该方法从第一个参数中就了解了要放什么类型
    List<Snow> snow3 = new ArrayList<Snow>();
    Collections.addAll(snow3, new Light(), new Heavy());

    //直接添加显式参数
    List<Snow> snow4 = Arrays.<Snow>asList(
       new Light(), new Heavy());
  • 注意List的indexOf、contains、remove依赖于equals的实现
  • Iterator可以移除由next()产生的最后一个元素,这意味着在调用remove之前必须先调用next()(不是当前指向的元素,上一次next调用后指向的元素);
  • LinkedList能够实现栈的所有功能同时也实现了Queue的接口,也可以拿来实现Stack.
  • Set有与Collection完全一样的接口 TreeSet使用了红黑树,HashSet使用的是散列函数
  • 任何实现Iterable接口的类,都可以用在foreach中,Map没有,Collection有
    增加Iterable的功能代码:
class ReversibleArrayList<T> extends ArrayList<T> {
  public ReversibleArrayList(Collection<T> c) { super(c); }
  public Iterable<T> reversed() {
    return new Iterable<T>() {
      public Iterator<T> iterator() {
        return new Iterator<T>() {
          int current = size() - 1;
          public boolean hasNext() { return current > -1; }
          public T next() { return get(current--); }
          public void remove() { // Not implemented
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }
}   

public class AdapterMethodIdiom {
  public static void main(String[] args) {
    ReversibleArrayList<String> ral =
      new ReversibleArrayList<String>(
        Arrays.asList("To be or not to be".split(" ")));
    // Grabs the ordinary iterator via iterator():
    for(String s : ral)
      System.out.print(s + " ");
    System.out.println();
    // Hand it the Iterable of your choice
    for(String s : ral.reversed())
      System.out.print(s + " ");
  }
}
  • new ArrayList(Arrays.asList(ia))和 Arrays.asList(ia)返回后的数组修改后,前者不改变ia,后者改变

异常处理

  • 使用logging工具将输出记录到日志中
class LoggingException extends Exception {
  private static Logger logger =
    Logger.getLogger("LoggingException");
  public LoggingException() {
    StringWriter trace = new StringWriter();
    printStackTrace(new PrintWriter(trace));
    logger.severe(trace.toString());
  }
}

public class LoggingExceptions {
  public static void main(String[] args) {
    try {
      throw new LoggingException();
    } catch(LoggingException e) {
      System.err.println("Caught " + e);
    }
    try {
      throw new LoggingException();
    } catch(LoggingException e) {
      System.err.println("Caught " + e);
    }
  }
} /* Output: (85% match)
Aug 30, 2005 4:02:31 PM LoggingException <init>
SEVERE: LoggingException
        at LoggingExceptions.main(LoggingExceptions.java:19)

Caught LoggingException
Aug 30, 2005 4:02:31 PM LoggingException <init>
SEVERE: LoggingException
        at LoggingExceptions.main(LoggingExceptions.java:24)

Caught LoggingException
*///:~
  • printStackTrace()方法所提供的信息可以通过getStackTrace()方法来直接访问
  • 重新抛出异常,更新异常的信息可以用fillInStackTrace()(抛出另一种异常,不会带有原来异常的信息)
  • 连接异常链用initCause()
  • 运行时异常不用手动try catch
  • finally块总会执行,即使之前有return,break出现的情况下

字符串

  • String是不可变的,每一个看起来像是修改了String值的方法,实际上都是创建了一个全新的String对象
  • 避免toString的递归(输出对象地址的时候)
public class InfiniteRecursion {
  public String toString() {
  //这里面用字符串连接this是执行toString,因此为无限递归,应该用super.toString()
    return " InfiniteRecursion address: " + this + "\n";
  }
  public static void main(String[] args) {
    List<InfiniteRecursion> v =
      new ArrayList<InfiniteRecursion>();
    for(int i = 0; i < 10; i++)
      v.add(new InfiniteRecursion());
      //执行toString方法
    System.out.println(v);
  }
}
  • System.out.format()方法可用于PrintStream或PrintWriter对象,该方法是模仿C的printf(),实际上内部是使用Formatter类实现的,String.format()方法也是如此
  • 正则表达式
    正则表达式插入一个普通的反斜线,应该这样“\\”,插入+号,应该用“\+”
    常见的使用:String.matches(“正则”) String.split(“正则”),String.replaceFirst,String.replaceAll()

类型信息

  • 运行时类型信息可以让你在程序运行时发现和使用类型的信息
  • 当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法。
  • getClass() 是object中的方法
  • class.forName()参数要包含包名
  • 使用newInstance()创建的类,必须带有默认的构造器
  • 建议使用“.class”的方式获得Class对象的引用,因为不用放在try-catch中
  • 仅使用.class语法来获得对类的引用不会引发初始化,但是Class.forName()立即就进行了初始化(指静态的值和方法)
  • 对于static final的值是“编译器常量”,不需要通过初始化就可以读取(通过产生随机数生成的static final的值除外)
  • 类型不会延续类的继承关系:
 public class GenericClassReferences {
     public static void main(String[] args) {
         Class intClass = int.class;
         Class<Integer> genericIntClass = int.class;
         genericIntClass = Integer.class; // Same thing
         intClass = double.class;
         // genericIntClass = double.class; // Illegal
     }
 }

但是不能这样写:

Class<Number> genericNumberClass = int.class;//即使Integer继承自Number
  • 泛型在使用子类类型得到超类类型时要使用模糊匹配:
public class GenericToyTest {
     public static void main(String[] args) throws Exception {
         Class<FancyToy> ftClass = FancyToy.class;
         // Produces exact type:
         FancyToy fancyToy = ftClass.newInstance();
         Class<? super FancyToy> up = ftClass.getSuperclass();
         // 这样写编译不了,哪怕类型是对的:
         // Class<Toy> up2 = ftClass.getSuperclass();
         // 而且这种情况下,使用该方法会只能得到Object类型,和上面的得到具体类型不一样:
         Object obj = up.newInstance();
     }
 }
  • 用于Class引用的转型语法:cast()方法
//House是Building的子类
public class ClassCasts {
    public static void main(String[] args) {
        Building b = new House();
        Class<House> houseType = House.class;
        House h = houseType.cast(b);
        h = (House)b; // 或者直接这样做也行.
    }
}

泛型

  • 泛型可以编译时检查参数,且不需要类型转换
public class Holder3<T> {
  private T a;
  public Holder3(T a) { this.a = a; }
  public void set(T a) { this.a = a; }
  public T get() { return a; }
  public static void main(String[] args) {
    Holder3<Automobile> h3 =
      new Holder3<Automobile>(new Automobile());
    Automobile a = h3.get(); // No cast needed
    // h3.set("Not an Automobile"); // Error
    // h3.set(1); // Error
  }
}
  • 如果泛型方法能做到,就不要用泛型类,静态方法无法访问泛型类的参数类型
  • 可变参数与泛型的使用:
public class GenericVarargs {
    public static <T> List<T> makeList(T... args) {
        List<T> result = new ArrayList<T>();
        for(T item : args)
            result.add(item);
        return result;
    }
    public static void main(String[] args) {
        List<String> ls = makeList("A");
        System.out.println(ls);
        ls = makeList("A", "B", "C");
        System.out.println(ls);
        ls = makeList("ABCDEFFHIJKLMNOPQRSTUVWXYZ".split(""));
        System.out.println(ls);
    }
}
  • 在泛型代码内部,无法获得有关泛型参数类型的信息
public class ErasedTypeEquivalence {
  public static void main(String[] args) {
    Class c1 = new ArrayList<String>().getClass();
    Class c2 = new ArrayList<Integer>().getClass();
    System.out.println(c1 == c2);
  }
} /* Output:
true
*///

IO

  • list()方法过滤器:
public class DirList2 {
  //需要实现这个接口用于回调
  public static FilenameFilter filter(final String regex) {
    // Creation of anonymous inner class:
    return new FilenameFilter() {
      private Pattern pattern = Pattern.compile(regex);
      public boolean accept(File dir, String name) {
        return pattern.matcher(name).matches();
      }
    }; // End of anonymous inner class
  }
  public static void main(String[] args) {
    File path = new File(".");
    String[] list;
    if(args.length == 0)
      list = path.list();
    else
      list = path.list(filter(args[0]));
    Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
    for(String dirItem : list)
      System.out.println(dirItem);
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值