[随笔][Java][something]

  • import 只能导入包中的类,不能导入某个包。为了方便,一般不导入单独的类,而是导入包下的所有类。import java.util.*;
  • 包java.lang中的所有类默认由编译器全部导入了,不必手动显示的导入。
  • import的搜索路径为环境变量中的CLASSPATH,一般将当前目录作为其中的一项“点.”添加到CLASSPATH中。
  • 一个类中的变量类型有三种:局部变量(在方法中或者语句块中定义的变量),成员变量(定义在类中,方法体之外的变量),类变量(定义在类中,方法体之外的,使用static修饰的变量)。
  • 在一个方法中使用成员变量,成员变量无论是否使用this进行调用,在编译的过程中都没有报错。但是如果成员变量的名字和方法的参数的名字一样,存在覆盖的效果。如果方法中不存在与成员变量一样的参数,则方法正常。
  • 构造方法一般不能显示的调用,但是可以在构造方法中通过super关键字显示的调用父类的构造方法。在继承体系中,如果父类没有提供无参构造函数,需要在子类的构造函数中通过super关键字显示的调用父类的构造函数;如果父类提供了无参构造函数或者有默认的无参构造函数,在子类中可以不显示的调用父类的构造函数。猜想的原理有两个,如果一个类没有定义构造函数,编译器默认添加一个无参构造函数,自定义构造函数了,编译器不添加任何构造函数;如果一个类继承某个类,在构造函数中没有显示的调用父类的构造函数,编译器默认调用父类无参函数。
  • java程序初始化顺序
父类静态变量 ->父类静态代码块 -> 子类静态变量 -> 子类静态代码块 -> 父类非静态变量 -> 父类非静态代码块 -> 父类构造函数 -> 子类非静态代码块 -> 子类非静态变量 -> 子类构造函数
  • java通过访问修饰符来控制类,属性和方法的访问权限和其他功能。java的修饰符分为访问修饰符和非访问修饰符。
  • 访问修饰符关键字总共有三个,权限控制类型有4种(多了一个默认的)。
  • private关键字不能修饰类和接口,否则会在编译的时候报错
  • 不使用任何修饰符的属性和方法,对一个包内的类是可见的。接口里的变量都隐式的声明为public static final,而接口里的方法都隐式的声明为public
  • 继承规则
1. 父类中声明为public的方法在子类中也必须为public。
2. 父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private。
3. 父类中默认修饰符声明的方法,能够在子类中声明为private。
4. 父类中声明为private的方法,不能够被继承。
  • java的变量的作用域分为4个级别:类级,实例级,方法级,块级。对于方法级和块级的变量,在使用之前必须初始化,否则不允许使用。

  • 对于this关键字,java默认把成员变量、成员方法和this关键字关联在一起,所以有些时候使用this关键字是多余的。
  • 在一个类的构造方法中,可以使用this关键字调用本类的其他构造方法。但是必须作为构造方法的第一句。
public class Demo{
    public String name;
    public int age;
   
    public Demo(){
        this("weixunyuan", 3);
    }
  
    public Demo(String name, int age){
        this.name = name;
        this.age = age;
    }
  
    public void say(){
        System.out.println("web site name " + name + ", are launched " + age + " year");
    }
  
    public static void main(String[] args) {
        Demo obj = new Demo();
        obj.say();
    }
}
  • 在一个构造方法中调用另外一个构造方法的语句必须在第一行;不能在构造方法之外的任何方法内调用构造方法;在一个构造方法内只能调用一个构造方法。使用this关键字做构造方法的重载。
  • this关键字也可以作为参数进行传递,表示的是当前对象的引用。
public class Demo{
    public static void main(String[] args){
        B b = new B(new A());
    }
}
class A{
    public A(){
        new B(this).print();    //匿名对象
    }
    public void print(){
        System.out.println("Hello from A!");
    }
}
class B{
    A a;
    public B(A a){
        this.a = a;
    }
    public void print() {
        a.print();
        System.out.println("Hello from B!");
    }
}
  • 匿名对象就是没有名字的对象,如果对象只使用一次,可以使用匿名对象。

  • 方法的重载(over load)指的是在同一个类中,相同的方法名,不同的参数。声明为final的方法不能重载,声明为static的方法不能被重载,但是能够被再次声明
  • 重载的方法的返回值类型可以相同也可以不相同,仅仅返回类型不同不足以成为方法的重载因素。
  • 对于初始化的顺序
public class Demo{
    A a = new A();

    public Demo() {
        System.out.println("demo");
    }

    public static void main(String[] args){
        Demo d = new Demo();
    }
}

class A {
    public A() {
        System.out.println("a");
    }
}

//输出结果
D:\Workspace\java>java Demo
a
demo
D:\Workspace\java>
  • java中定义一个包,在语法层面需要使用package关键字定义,在文件系统层面需要按照包的名字将源码文件放到对应的位置。一个包中还可以包含其他的包。????
  • 执行javac命令需要进入到当前目录,执行java命令需要进入当前目录的上级目录,并且类名前面要带上包名。?????

java的继承和多态

  • 子类可以继承父类中除了private的所有成员。
  • 类是单继承,接口允许多继承。
  • super关键字的三个作用:调用父类中声明为private的变量,获取已经覆盖的方法,作为方法名表示父类的构造方法。

  • 覆盖:在子类中创建一个方法,名称,参数列表,返回值都和父类中的相同。则子类中的方法覆盖父类中的方法。被覆盖的方法在子类中通过super调用。
  • 在子类中写方法对父类中的相应方法进行覆盖的时候,需要注意权限访问符的级别,返回值类型,方法名,参数列表。
1. 访问修饰符,子类中覆写的方法的访问权限修饰符级别要低于父类中的,也就是子类方法应具有高广的访问范围。如果父类的方法是private,则子类的覆写概念不成立,因为子类不会继承父类为private的成员,子类怎么写都无所谓。默认包权限 > protected > public
2. 子类的覆写的方法只覆写父类中的某个方法,如果父类中的有多个方法进行重载,则子类的方法只覆写其中的一个,其他的方法还是使用继承过来的方法。
3. 覆盖方法的返回类型、方法名称、参数列表必须与原方法的相同。
4. 覆盖方法不能比原方法访问性差(即访问权限不允许缩小)。
5. 覆盖方法不能比原方法抛出更多的异常。
6. 被覆盖的方法不能是final类型,因为final修饰的方法是无法覆盖的。
7. 被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
8. 被覆盖的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足覆盖条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足覆盖条件,但是仍然不会发生覆盖,因为**静态方法是在编译的时候把静态方法和类的引用类型进行匹配**。
  • 如果子类中进行方法的覆写,那么父类中的那些没有被覆写的方法和子类中的方法一起进行重载。

  • 一个多态的例子
public class Demo {
    public static void main(String[] args){
        Animal obj = new Animal();
        obj.cry();
        obj = new Cat();
        obj.cry();
        obj = new Dog();
        obj.cry();
    }
}
class Animal{
    public void cry(){
        System.out.println("animal\n");
    }
   
}
class Cat extends Animal{
    public void cry(){
        System.out.println("cat\n");
    }
}
class Dog extends Animal{
    public void cry(){
        System.out.println("dog\n");
    }
}
  • 多态的三个条件:有继承,有重写,父类变量引用子类对象。
  • 重载是在一个类的范围内,不涉及继承,重写是在子类和父类范围内,涉及继承。

  • 这块应该了解一下java的内存模型。对于每个对象,存储的是成员变量。在类定义的部分,如果继承了父类的方法,应该有个父类中该方法的入口地址。如果子类对该方法进行了覆写,那么子类中这个位置就是自己的方法的入口地址。对于多态的方法,在父类中首先应该存在这个方法,不然,沿着继承链向上,可能会没有这个方法,因此在进行多态的时候,首先检查父类中是否存在这个方法
  • 多态是面向对象的概念,java通过动态绑定实现多态。多态是概念,动态绑定是技术。

  • 动态绑定流程
1. 编译器查看对象的声明类型和方法名。
2. ???
  • 如果想实现多态,需要解决一个问题,就是如何判断一个变量所实际引用的对象的类型。C++使用TRRI,java使用instanceof操作符。
public final class Demo{
    public static void main(String[] args) {
        People obj = new Teacher();
        if(obj instanceof Object){
            System.out.println("i am a object\n");
        }
        if(obj instanceof People){
            System.out.println("i am human\n");
        }
        if(obj instanceof Teacher){
            System.out.println("i am a teacher\n");
        }
        if(obj instanceof President){
            System.out.println("i am caption\n");
        }
        
    }
}
class People{ }
class Teacher extends People{ }
class President extends Teacher{ }

//输出
D:\Workspace\java>java Demo
i am a object
i am human
i am a teacher
D:\Workspace\java>
  • 如果变量引用的是当前类或者他的子类的实例,instanceof返回true,否则返回false

  • 对象的类型转化,指的是存在继承关系的类的对象之间的转化。子类向上转换称为向上转型,父类向子类转换成为向下转型。使用父类的变量引用子类的实例,称为向上转型。将向上转型后的子类对象再转成子类,称为向下转型,调用子类的方法就是向下转型。
  • 不能将父类的对象直接转换成子类的对象,只能将向上转型后的子类对象向下转型。也就是子类对象必须向上转型后才可以向下转型。如果直接将父类对象向下转型称为子类对象,编译的时候不会出错,但是在运行的时候会出错。
public class Demo {
    public static void main(String args[]) {
        SuperClass superObj = new SuperClass();
        SonClass sonObj = new SonClass();
        // SonClass sonObj2 = (SonClass)superObj;
        superObj = sonObj;                                        //向上转型
        SonClass sonObj1 = (SonClass)superObj;    //向下转型
    }
}
class SuperClass{ }
class SonClass extends SuperClass{ } 

java的高级特性

  • java允许内部类(嵌套类)的存在。在一个类的内部,在一个方法体中,在一个语句块中,都可以定义另外一个类,称为内部类。
  • 内部类和外部类之间存在所属关系,一般只用在定义他的类或语句块之内。实现一些没有通用意义的功能。在外部引用内部类的时候,需要给出完整的名称。
  • 内部类的用途:
内部类可以访问外部类中的数据,包括私有的数据。
内部类可以对同一个包中的其他类隐藏起来。
**当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。**
减少类的命名冲突。
public class Outer {
    private int size;
    public class Inner {
        private int counter = 10;
        public void doStuff() {
            size++;
        }
    }
    public static void main(String args[]) {
        **Outer outer = new Outer();**
        **Inner inner = outer.new Inner();**        //必须先定义外部对象,才能生成内部类的对象。
        inner.doStuff();
        System.out.println(outer.size);
        System.out.println(inner.counter);
        System.out.println(counter);    //不可以直接访问内部类的私有变量,但是可以使用inner.counter的方式进行访问。
    }
}
  • 内部类是编译器行为,是虚拟机无感知的,生成特殊名字的字节码文件

java泛型

  • 针对不同的数据类型,除了可以使用重载,还可以借助自动装箱和向上转型。
public class Demo {
    public static void main(String[] args){
        Point p = new Point();

        p.setX(10);  // int -> Integer -> Object
        p.setY(20);
        int x = (Integer)p.getX();  // 必须向下转型
        int y = (Integer)p.getY();
        System.out.println("This point is:" + x + ", " + y);
       
        p.setX(25.4);  // double -> Integer -> Object
        p.setY("东京180度");
        double m = (Double)p.getX();  // 必须向下转型
        double n = (Double)p.getY();  // 运行期间抛出异常
        System.out.println("This point is:" + m + ", " + n);
    }
}

class Point{
    Object x = 0;
    Object y = 0;

    public Object getX() {
        return x;
    }
    public void setX(Object x) {
        this.x = x;
    }
    public Object getY() {
        return y;
    }
    public void setY(Object y) {
        this.y = y;
    }
}
  • 向下转型存在风险,且在编译的期间不容易发现

  • 使用泛型的例子。
public class Demo {
    public static void main(String[] args){
        // 实例化泛型类
        Point<Integer, Integer> p1 = new Point<Integer, Integer>();
        p1.setX(10);
        p1.setY(20);
        int x = p1.getX();
        int y = p1.getY();
        System.out.println("This point is:" + x + ", " + y);
        
        Point<Double, String> p2 = new Point<Double, String>();
        p2.setX(25.4);
        p2.setY("东京180度");
        double m = p2.getX();
        String n = p2.getY();
        System.out.println("This point is:" + m + ", " + n);
    }
}
// 定义泛型类
class Point<T1, T2>{
    T1 x;
    T2 y;
    public T1 getX() {
        return x;
    }
    public void setX(T1 x) {
        this.x = x;
    }
    public T2 getY() {
        return y;
    }
    public void setY(T2 y) {
        this.y = y;
    }
}
  • 泛型的类的定义中,增加了类型参数。

猜你喜欢

转载自www.cnblogs.com/person3/p/9541319.html