Java笔记

Java 笔记

  • 每个java源文件只能有一个public类型的类,并且此类要和文件名相同。

  • 实例变量永远都会有默认值,即使没有显式赋值。

默认值:

int     0
float   0.0
boolean false
引用      null
  • ==对于primitive主数据类型来说,是进行字节比较,而引用类型的话,则是比较是否引用的是同一个对象

  • java中跨类型转换(比如从String到int),需要调用内建类来完成转换。比如,Integer.parseInt("3")

  • for-in循环来遍历的时候,调用的只是副本

  • java的随机数由Math类的random()方法提供,产生一个介于0到1之间的小数。

  • 类似 (int) ,成为cast运算符,即强制类型转换。

  • 关于抽象类与抽象方法

    • Java天生支持(运行时多态),而C++则必须用 virtual 关键字修饰函数才能实现。

    • C++的纯虚函数才相当于Java的抽象方法。

    猜想:因为Java强制面向对象,所以不会有全局的函数,所以可能就不需要像C++那样来区分全局函数和成员函数。同理纯虚函数和函数声明可能也有类似的关系。

    猜想:非抽象类的所有成员都会被“构造出实体”,所以非抽象类才不能有抽象方法。Java这种用抽象类来约束抽象方法的行为,可能比C++那种反过来约束要好一些。

  • 关于继承与多态

    • java不允许多继承,所以一个类只可以继承(extends)一个普通类。但同时可继(implements)承多个接口。
    • java声明为父类的引用可以被赋值子类的实体,但是只能调用父类的方法。
  • 抽象类与接口

    • 抽象类允许有非抽象函数,即允许有被实际定义了的函数。
    • 接口则不允许有非抽象函数。
    • 子类只能继承一个抽象类,但可以继承多个接口。
    • 接口必须被实现,而抽象类可以被抽象类继承。
    • 类继承的概念是垂直的,而接口实现的概念是平行的。哈士奇类继承狗类,狗类继承动物类,哈士奇必是动物。

    所以使用接口必不会出现钻石继承,因为任何一个接口必没有父类(接口)

    • 而又由于接口必被实现,不能有父接口的存在,所以根本堆叠不起来,也就不会有垂直一说。所以,哈士奇类如果用接口来完成的话就是同时实现狗接口和动物接口。但这是不合理的,因为狗都是动物,它们是自然存在堆叠关系的。所以,哈士奇类实现犯二接口和嚎叫接口是合理的。

    可以看出,类和接口虽然类似但是根本不是同一种东西。类是确定的一以贯之的,就像商城里商品的分类,而接口是灵活的描述性的,就像商品的标签

    • 接口还有一个重要的地方就是,首先它不能有成员变量,其次它的所有方法必须都是public的。因为首先default和private是肯定不行的(因为这样就对子类隐藏了),然后如果是protected的话,接口的多态将形同虚设,因为一旦被定义为protected其他包便无法访问了。

    • 还有个有趣的地方是接口不仅能被implements,还能被extends。也就是说普通类实现接口,而接口则可以继承自另一个接口。

  • 关于成员访问权限

    • 在java中,子类不能将父类成员方法的权限缩小,但可以放大(如protected变为public)。
    • 而成员变量的权限则不能被修改。

    因为假设一个接口定义了一套规则,保证一个实现此接口的任何一个子类都能有此方法可调用,但是若被子类改成private就尴尬了

  • 关于静态和非静态方法

    • 静态方法是属于类的,不属于单独的对象。
    • 非静态方法是属于每一个对象的,不属于类。

    其实,某种意义上说,静态方法就是过程式编程中的函数,即就想要某个特定的功能,而不属于什么客观事物关系。即使属于某个类也只是简单的分类,而没有逻辑上的堆叠关系,也就是说静态方法前的类名,一定意义上起了一个名字空间的作用。

    • 非静态方法可以调用静态方法,而静态方法则不能(直接)调用非静态方法(不论本类内外)。
    • 本类中非静态方法可以调用非静态方法,但不能(直接)调用其他类的非静态方法。
    • 静态方法任何时候都可以互相调用。

    其实以上问题就是个实例化的问题:非静态方法除了在本类非静态方法中,在其他任何地方的调用,都需先把类实例化为对象再调用。

  • 关于方法调用

有个很有意思的对比:

代码1public class ClassTest {
    public static void main(String[] args){
        A a = new B();
        a.get();
    }
}

class A{
    int a = 0;

    public void get(){
        System.out.println(a);
    }
}

class B extends A{
    int a = 1;
}

输出: 0

代码2public class ClassTest {
    public static void main(String[] args){
        A a = new B();
        a.get();
    }
}

class A{
    int a = 0;

    public void get(){
        System.out.println(a);
    }
}

class B extends A{
    int a = 1;

    public void get(){
        System.out.println(a);
    }
}

输出: 1

这说明了2个(其实是显而易见的)问题:

  1. 用父类的引用变量去操纵子类的对象时,方法优先用子类覆盖的版本(符合逻辑)。
  2. 而第一个例子也说明,实例变量的作用域只在类中。所以,本类的方法只能访问本类的变量(不附加其他任何条件的情况下)。
  3. 还有一个重要的事!那就是覆盖只是对函数的,变量并不会被覆盖!也就是说,如果子类中有与父类同名的变量,父类的那个变量没有被覆盖掉!

    • 关于常量的定义

    • 我的老师说,用static修饰的变量就是常量,其实不是的,因为它可以被子类覆盖而且还可以被静态方法修改。

    • 只有用final和static两个修饰符修饰的变量,才可以当常量使用。

    • 关于覆盖与重载

    • 覆盖是指重写一个与父类(或实现的接口)中方法形式(返回值和参数以及函数名)完全一致的新方法。

    • 而重载则是写一个与已存在方法同名但不同参数表的新方法。

所以下面这段代码既不是覆盖也不是重载,根本不会通过编译

class A{
    int a(){
        ...
    }
}

class B extends A{
    double a(){
        ...
    }
}
  • 关于迭代器与for-get遍历、foreach遍历

    • 首先我想说的是:输出是很耗时的!测性能的时候一定不要带输出!!
    • 本来我天真的以为:迭代器在任何时候都是比for-get遍历快的,因为我用LinkedList测试的时候,后者的性能比前者差好多。
      可是我却忘了链表本身遍历上的特点,链表用朴素方法遍历的时候效率是十分低的,这才造成了以上错觉。
    • 所以,等我换了ArrayList再来测试的时候发现,情况逆转了,虽然差距不是特别大,但for-get的性能还是优于迭代器的。

    由此我们便可得出结论: 在顺序存储结构下,迭代器慢于for-get遍历,而在链式存储结构下则相反。

    • 然而更有趣的是,当我们把foreach遍历也加进来看的时候。

    最终比较结果如下:

    存储结构性能
    顺序迭代器<foreach<for-get
    链式for-get<迭代器<foreach

    值得注意的是,在顺序存储结构下,三种遍历方法的性能差别其实是微乎其微的。而在链式存储结构下差别则十分明显,foreach真的是巨快,而相应的for-get真的是慢出翔

  • 关于static方法

    • 首先被加了 static 的方法就不是对象的方法了,而是类的方法。其实在我看来,这就是让一个类的方法变成了一个函数。因为它不再需要先把类实例化成对象再用,可以直接使用。
    • 还有一个问题是,关于this的。在static修饰的方法中不能用this,因为没有对象,所以如果要区分类的成员变量和其他变量时可以用类名.变量名的方式。

持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值