Java基本知识点

本文详细介绍了Java编程中的核心概念,包括数据类型转换、运算符、控制流程、类和对象、继承、多态、异常处理、泛型、反射以及动态代理。讲解了变量初始化、构造器、方法重载、final关键字的用法、接口与内部类、集合框架、异常处理策略以及泛型和反射在实际编程中的应用。内容深入浅出,旨在帮助开发者更好地理解和运用Java编程语言。
摘要由CSDN通过智能技术生成

1、Java不会自动地将int数值转换成布尔值

2、将float或double转型为整型值时,总是对该数字执行结尾。四舍五入使用Math.round()

3、如果对基本数据类型执行算术运算或按位运算,只要类型比int小(byte、char或short),那么在运算之前,会自动转换成int,最终结果都是int。通常表达式中出现的最大数据类型决定表达式最终结果的数据类型。例:如果将int和long相加,结果为long

4、在C/C++中,sizeof()求字节数。但是,在Java中所有数据类型在所有机器中的大小都是相同的,不需要该方法。

5、while在循环刚开始时,会计算一次布尔表达式的值;而在语句的下一次迭代开始前再计算一次

     do-while则第一次不需要计算直接执行,至少会执行一次。

6、break用于强行退出循环,不执行循环中剩余的语句;

     continue停止当前的迭代,然后退出循环起始处,开始下一次迭代

7、switch适用于:char、byte、short、int、Character、Byte、Short、Integer、String、Enum。不适用于long、float、double、对象等。

    switch需要在有限的集合中选择,与enum是绝佳的使用组合。

8、重载是由参数区分的,那么可以使用返回值区分吗?

void hello() {
    System.out.println("hello java");
}

String hello() {
    return "hello java";
}
此时,如果不关心返回值时,就会出现:
hello();
根本没有办法区分hello()调用到底是上面哪种

9、如果你写的类中没有构造器,编译器会自动生成一个默认构造器;但是如果已经定义了构造器,编译器不会再生成默认构造器。

10、如果只有一个方法hello(String message),hello如何判断是哪个对象调用的呢?

public class Demo{
   public void hello(String message) {
        System.out.println(message);
   }
}

public class App {
    public static void main(String[] args) {
        Demo demo1 = new Demo();
        Demo demo2 = new Demo();
        demo1.hello("World");
        demo2.hello("Java");
    }
}

    编译器会将对象引用作为方法的第一个参数:Demo.hello(demo1, "World");

    在方法内部使用this就是调用该方法的对象引用

11、this(,,……)可以用于在构造函数中调用构造函数,且必须放在最起始处,否则编译器会报错。

12、static方法就是没有this的方法,在static方法内部不能直接调用非静态方法【可以使用对象的引用调用】,反过来可以。static具有全局函数的语义。

       printDemo(message) -> this.printDemo(message) -> Demo.printDemo(this, message); 而在static是没有this的方法,static是属于class的

public class Demo {
   public static void print(String message) {
       printDemo(message); 
       Demo demo = new Demo();
       demo.printDemo(message);
   }

   public void printDemo(String message) {
       System.out.println(message);
   }
}

13、finalize():垃圾回收器准备释放对象占用的存储空间时,会调用对象的finalize(),然后在下一次垃圾回收时,回收对象。问题就是垃圾回收器回收对象是不定的,所以finalize()与C++中析构函数并不对等。

        垃圾回收器会自动回收Java中对象,而在Java中一切皆对象,所以在finalize()中并不适用清理对象内存,将finalize()的作用限制到:本地方法申请的内存空间。如:C的malloc(),那就在finalize()调用本地方法free()释放内存空间。

14、所有变量在使用前都能得到初始化;而在类中定义一个对象,如果不初始化,引用则会得到一个特殊的值null;对于方法的局部变量,会编译报错。未初始化变量编译器直接赋初值容易掩盖错误。

15、初始化顺序

       在类的内部,变量定义的顺序决定初始化顺序,即使散步在方法间,仍然会在任何方法被调用之前初始化

       先静态对象,而后是“非静态”对象。

16、静态初始化只执行一次:当首次生成这个类的对象或调用类的静态数据成员时。

17、可变参数列表:可变参数列表当你传入参数时,编译器会去填充数组,获取到的仍然是一个数组。如果有一组事务,可以作为参数列表传递,而如果已经有一个数组,该方法同样可以将他们当做可变参数列表接受。

public static void main(String[] args) {
    print("hello", "java");
    System.out.println();
    print(new Integer[] {1, 2, 3});
}

private static void print(Object... args) {
    for (Object object : args) {
       System.out.print(object + " ");
    }
}

private static void print(String name, Object... args) {
    System.out.ptin(name + " ");
    for(Object object : args) {
       System.out.print(object + " ");
    }
}

   可变参数列表会使重载变得比较复杂:编译器会调用最明显匹配的方法;最好只在重载方法的一个版本上使用可变参数列表,或者最好不使用。

    编译错误

public void f(float i, Character... args) {
    System.out.println("first");
}

public void f(Character... args) {
    System.out.println("second");
}

public static void main(String[] args) {
    OverloadingVarargs2 varargs2 = new OverloadingVarargs2();
    varargs2.f(1, 'a');
    varargs2.f('a', 'b');
}

18、enum

       当创建enum时,编译器会自动添加一些有用的特性:

        toString(): 显示enum实例的名字;ordinal(): 表示某个特定enum常量的声明顺序;static values():按照enum常量的声明顺序,产生由常量构成的数组。

19、package和import的作用的是提供class的命名空间,避免class名字冲突。

20、Java解释器的运行过程如下:找到环境变量CLASSPATH,CLASSPATH包含一个或多个目录,用作查找class的根目录,从根目录开始,解释器获取包的名称并将每个包点替换成反斜杠,与CLASSPATH目录产生全路径,解释器就在这些目录中查找与你想要创建的类名称相关的.class文件。如果运行时,遇到找不到类,可以根据CLASSPATH来分析。

21、访问权限的控制:具体实现的隐藏,把数据和方法包装进类中,以及具体实现的隐藏,即封装

       包访问权限:默认访问权限没有任何关键字,指包访问权限。由于一个编译单元(即一个文件)只能隶属于一个包,所以经由包访问权限,处于同一个编译单元中的所有类彼此之间都是可以自动可访问的。

       public:public后紧跟着的成员对每个人都是可用的

       private:除了该成员的类之外,其他任何类都无法访问这个成员。private不对外提供,允许随意改变成员,而不必考虑是否会影响其他类;而且,如果默认构造器是唯一定义的private构造器,将阻碍此类的继承。

       protected:继承访问权限 && 包访问权限。基类创建者希望某个特定成员,把对它的访问权限赋予派生类而不是所有类。尽可能隐藏,但仍然想要导出类中访问它。

      每个编译单元(文件)都只能有一个public类:每个编译单元都有单一的公共接口,用public类来表现。可以包含众多的支持包访问权限的了。如果在某个编译单元内有一个以上的public类,编译器就会给出出错信息。编译单元内完全不带public类也是可能的,在这种情况下,可以随意对文件命名。

      类不能为private、protected的。类仅有两个访问权限:包访问权限或public。一个内部类可以是private或protected的。

22、面向接口编程,也是将public方法对外提供,而具体的实现则封装在具体实现中。封装的进一步体现。

23、控制对成员的访问权限的原因:

       1)使用户不要碰触那些他们不该碰触的部分。用户可以有效的分清主次;

       2)  类库设计者可以更改类的内部工作方式,而不必担心会对调用方产生重大的影响。

24、继承,子类会自动得到基类中所有的域和方法

25、+、+=操作符被Java设计者重载用以处理String对象

26、Java会自动在导出类的构造器中插入对基类构造器的调用;构造过程是从基类向外扩散,所以基类在到处类构造器可以访问它之前,就已经完成了初始化。即使导出类没有构造器,编译器也会合成一个默认的构造器,并在构造器中调用基类的构造器。

      如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显示地编写调用基类构造器的语句。

27、@Override注解可以防止你在不想重载时意外进行了重载:重载既可以是同一个类中,也可以是在基类和导出类间

28、组合和继承都允许在新类中放置子对象,组合是显式,继承是隐式。组合通常用于想在新类中使用现有类的功能而非它的接口;继承使用现有类,并开发一个它的一个版本,新类就是现有类的一种类型,继承可以确保在基类中的所有方法在导出类中有效,因此,能够向基类发送的所有请求,导出类同样可以处理。组合是has-a的关系,继承是is-a的关系。

29、向上转型:基类-导出类。将导出类引用当做基类来使用就是向上转型,导出类是基类的超集,所以是安全的,但是可能会缩小导出类的接口。

30、组合和继承的选择:has-a与is-a的选择、是否需要向上转型。

31、static final和final的区别:static在装载时已被初始化,而不是每次创建对象时都初始化

public class FinalDemo {
    private static final Random random = new Random(100);

    private final int hello = random.nextInt(20);
    private static final int world = random.nextInt(20);

    @Override
    public String toString() {
        return "hello: " + hello + ",world: " + world;
    }

    public static void main(String[] args) {
        System.out.println(new FinalDemo());
        System.out.println(new FinalDemo());
    }
}

32、final域必须在定义或构造函数中初始化,保证使用前必须初始化;final参数保证方法中只能读参数不能修改参数。

33、final数据:永不改变的编译时常量;在运行时被初始化的值,而你不希望改变它。

34、final方法:不允许被导出类覆写的方法。final针对的是覆写,因此,private方法默认就是final的,无法被导出类使用和覆写,private方法隐含就是final的。

35、final类:不允许继承。final类中的数据添加final具备33的特点,但是类中的方法,添加与否都不会有任何影响。

36、将一个方法调用和方法体关联起来就被称作绑定:若在程序执行前进行绑定(编译器和连接程序实现),叫做前期绑定; 运行时根据对象的类型进行绑定,就是后期绑定(运行时绑定)。Java中除了static和final方法外,其他所有方法都是后期绑定。这也是多态的保证。

37、多态依靠的是后期绑定,自然static、final方法,字段等就不具备多态的特性。

38、构造器的调用顺序:基类构造器-按声明调用成员的初始化方法-导出类的构造器。基本能够保证导出类中可以使用基类的public、protected方法,以及当前导出类的成员对象都被初始化了。

39、协变返回类型:导出类中覆盖的方法的返回类型可以是基类方法返回类型的某种导出类型。

40、用继承表达行为上的差异,用字段表示状态的不同。组合能够动态的选择类型,更新灵活;继承在编译时就知道具体的类型。

public class Transmogrify {
    public static void main(String[] args) {
        Stage stage = new Stage();
        stage.performPlay();
        stage.change();
        stage.performPlay();
    }
}

class Actor {
    public void act() {}
}

class HappyActor extends Actor {
    public void act() {
        System.out.println("HappyActor");
    }
}
class SadActor extends Actor {
    public void act() {
        System.out.println("SadActor");
    }
}
class Stage {
    private Actor actor = new HappyActor();
    public void change() {
        actor = new SadActor();
    }
    public void performPlay() {
        actor.act();
    }
}

41、abstract和private是不能一起使用的。

42、interface中的域隐式的是static & final的,方法隐式是public的,不能为protected、private等。       

43、如果一个方法操作的是类,它只能接受类和导出类。但是接口可以放宽这种限制,更加灵活。

44、当类继承基类与实现多个接口时,继承在前,接口再后,否则编译器会报错。

45、使用接口的原因:可以向上转型为多个基类型、接口和抽象类一样都能防止客户端程序员创建该对象。

46、接口可以嵌套在其他类或其他接口中。当嵌套在class中,可以使用private、protected修饰,当嵌套在interface中,不可以使用。当实现某个接口时,不需要实现嵌套在接口内部的接口,且private接口不能再定义它的类外部发现,即使在定义它的内部使用public class实现,在外部难以使用,阻止了向上转型。【9.8】

47、恰当的选择是优先选择类,而非接口。从类开始,如果接口的必需性变得非常明确,那么就进行重构,接口是一种工具,容易被滥用

48、当外部类使用内部类时,和使用其他任何类的方式是一样的,但是外部类能够访问内部类的任何域和方法;而内部类同样具有外部类所有元素的访问权,是因为构建内部类的时候内部类保留了指向外部类的引用

public class OuterClass {
    private String hello = "Hello";
    class InnerClass {
        private String world = "World";
        private String string() {
            // 可以直接访问外部类的私有域和方法
            return hello + world;
        }
    }
    public String toString() {
        // 与使用其他类一样,但是可以使用内部类的私有域和方法
        InnerClass innerClass = new InnerClass();
        System.out.println(innerClass.world);
        return innerClass.string();
    }
    public static void main(String[] args) {
        System.out.println(new OuterClass().toString());
    }
}
class OtherClass {
    public static void main(String[] args) {
        OuterClass.InnerClass innerClass = new OuterClass().new InnerClass();
        // 不能访问内部类的私有方法或私有域
        //System.out.println(innerClass.string());
    }
}

49、如果想在内部类中获取外部类的对象的引用:Outer.this即可

        如果想要创建内部类时: Outer outer = new Outer(); Inner inner = outer.new Inner();需要外部类对象,因为内部类是连接到创建它的外部类上。而创建的嵌套类则不需要(静态内部类)。

public class Outer {
    void f() {
        System.out.println("DotThis.of()");
    }

    public class Inner {
        public Outer outer() {
            // "this"表示Inner's "this"
            return Outer.this;
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner dti = outer.new Inner();
        dti.outer().f();
    }
}

50、匿名内部类可以扩展类或实现接口,但不可同时兼备,比正规的继承相比受限。

51、如果不需要内部类对象与其外部类对象有关联,只需要将内部类声明为static,嵌套类。嵌套类意味着:要创建嵌套类对象,不需要其外部类的对象;不能从嵌套类的对象中访问非静态的外部类对象;普通内部类中不能包含static字段和方法,而嵌套类能包含所有的一切

52、一个内部类被嵌套多少层不重要,它能透明地访问所有它所嵌入的外围类的所有成员

53、内部类有一些特性:可以实现多重继承、内部类的创建不会因为外部类的创建而创建。内部类的价值应该是在可以随意访问外部类的域。

54、Java类容器分为两类:Collection[List、Set、Queue]、Map

55、Iterator可以移除由next()产生的最后一个元素,这意味着调用remove前,需要先调用next()。Iterator能够将遍历元素的操作与序列底层的结构分离。

public class CrossContainerIteration {
    public static void display(Iterator<Pet> iterator) {
        while (iterator.hasNext()) {
            Pet pet = iterator.next();
            System.out.print(pet.id() + ":" + pet + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List<Pet> pets = Pet.arrayList(8);
        LinkedList<Pet> petLinkedList = new LinkedList<>(pets);
        HashSet<Pet> petHashSet = new HashSet<>(pets);
        display(pets.iterator());
        display(petLinkedList.iterator());
        display(petHashSet.iterator());
    }
}

56、ListIteator是Iterator更加强大的子类,用于各种List的访问。Iterator只能向前移动,ListIterator可以双向移动。

57、Queue

 Throws exceptionReturns special value
Insertadd(e)offer(e)
Removeremove()poll()
Examineelement()peek()







 

58、可以在声明方法时使用throws抛出异常,实际上却不抛出。后续就可以优雅的抛出这种异常而不需要修改接口。尤其是在抽象类和接口中特别适用。

public class ExceptionMethods {
    public static void main(String[] args) {
        try {
            throw new Exception("My Exception");
        } catch (Exception e) {
            // 用来获取详细信息,或用本地语言表示的详细信息
            System.out.println("getMessage():" + e.getMessage());
            System.out.println("getLocalizedMessage():" + e.getLocalizedMessage());
            // 返回对Throwable的简单描述,要是由详细信息的话,也会包含在内
            System.out.println("toString():" + e.toString());
            // 打印Throwable和Throwable的调用栈轨迹
            e.printStackTrace(); // 输出到标准错误
            e.printStackTrace(System.err); // 允许选择要输出的流
            // 每个方法都比前一个提供更多的信息-他们每一个都是前一个的超集
        }
    }
}
result:

getMessage():My Exception
getLocalizedMessage():My Exception
toString():java.lang.Exception: My Exception
java.lang.Exception: My Exception
	at springdemo.tacocloud.chapter12.ExceptionMethods.main(ExceptionMethods.java:10)
java.lang.Exception: My Exception
	at springdemo.tacocloud.chapter12.ExceptionMethods.main(ExceptionMethods.java:10)

59、无意识递归

class InfiniteRecursion {
    @Override
    public String toString() {
        // String + 非String:编译器会尝试将非String通过toString()方法转换为String,会递归
        // 可以使用super.toString()
        return "InfiniteRecursion address:" + this;
    }
    public static void main(String[] args) {
        InfiniteRecursion infiniteRecursion = new InfiniteRecursion();
        System.out.println(infiniteRecursion);
    }
}

60、Class对象的引用

       通过Class对象的引用,可以了解类型信息,生成实例对象等。

       Class.forName(String className):如果className会立即进行初始化;如果找不到className会抛ClassNotFoundException

      如果有Class的实例对象,可以通过getClass()来获取Class引用

      类名.class也可以获取Class引用,不会自动初始化。初始化被延迟到了对静态方法(构造器也是静态方法)和非常熟静态域进行首次引用时才执行。static final的编译期常量可以直接获取不需要初始化,如:static final int staticFinal = 123,而static final int staticFInal1 = new Random().nextInt(3)则不是编译期常量,会引起初始化。

61、Class+泛型

    public static void main(String[] args) throws Exception{
        // Class+泛型,newInstance()是该对象的确切类型
        Class<FancyToy> ftClass = FancyToy.class;
        FancyToy fancyToy = ftClass.newInstance();
        
        // This won't compile
        // Class<Toy> up2 = ftClass.getSuperclass();
        Class<? super FancyToy> up = ftClass.getSuperclass();
        // 此处也就只能返回Object
        Object toy = up.newInstance();
    }

62、Class的等价性

       instanceof和isInsance生成的结果一致,保留了类型的概念“你是这个类吗?你是这个类的派生类吗?”;equals和==生产的结果一致,比较实际的Class对象,不考虑继承关系。

63、RTTI和反射

       如果不知道某个对象的确切类型[多态、instanceof],RTTI可以告诉你。限制:这个类型必须在编译时已知,RTTI就可以识别。

       如果某个类在编译器为你生成代码后很久才会出现,那么怎么才能使用这样的类呢?

       Class类与java.lang.reflect类库一起支持反射的概念。Field、Method、Constructor类。这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。

       RTTI和反射真正的区别是:对RTTI来说,编译器在编译时打开和检查.class文件(可以用“普通”方式调用对象的所有方法),而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件[要么在本地机器上,要么可以通过网络取得]。

64、反射是用来支持像对象序列化、JavaBean等特性的。但是,如果能动态地提取某个类的信息时,反射还是很有用的。

65、Proxy.newProxyinstance()创建动态代理,参数:一个类加载器(可以从已经被加载的对象中获取其类加载器,然后传递给它);希望该代理实现的接口列表(不是类或抽象类);InvocationHandler接口的一个实现(具体被代理的实现)。

66、如果某个接口类提供给其他程序员使用,而程序员在使用接口类时,向下转型,会导致接口类的实现类中某些添加的public方法会暴露出去,导致两侧的代码耦合度增加。如果想要阻止,使用包访问权限即可。

67、泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节。

68、是否拥有泛型方法,与其所在的类是否为泛型没有关系。对于一个static方法而言,无法访问泛型类的泛型参数,如果static方法需要使用泛型能力,必须使它成为泛型方法。泛型方法,只需要将泛型参数列表置于方法的返回值前。

69、当使用泛型类的时候,必须在创建对象的时候指定类型类型参数的值,而使用泛型方法的时候,通常不必指明参数类型。这称为类型参数推断(type argument inference)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值