Java优秀教程
阅读原文时间:2023年07月08日阅读:1

1、java中局部变量是在栈上分配的;

2、数组是储存在堆上的对象,可以保存多个同类型变量;

3、在Java语言中,所有的变量在使用前必须声明。

4、局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

5、内置类型有默认值,引用对象的默认值是null;

6、非静态实例变量、非静态方法是通过对象实例进行调用的,不能直接从静态方法中调用;比如java源文件中main方法中不可以直接调用非静态方法;

7、静态变量、实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。

8、在构造方法中,当实例变量的名称跟局部变量的名称一致时,实例变量的使用就要用this了。

9、静态变量(类变量)除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。

10、静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。

11、类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。

12、方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。

13、类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。

14、 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

15、String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了。如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。

16、Java 语言中提供的数组是用来存储固定大小的同类型元素。

17、java遍历二维数组:

运行结果:

18、休眠三秒:

运行结果:

19、计算日期间隔:

运行结果:

20、从控制台读取数据

带reader的是字符流

// 使用 BufferedReader 在控制台读取字符

// 使用 System.in 创建 BufferedReader

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

从控制台读取字符串

str = br.readLine();

从控制台读取多字符输入

c = (char) br.read();

21、控制台输出

PrintStream 继承了 OutputStream类,并且实现了方法 write()。这样,write() 也可以用来往控制台写操作。

注意:write() 方法不经常使用,因为 print() 和 println() 方法用起来更为方便。

字节流写文件易出现乱码(字节流是二进制)

不使用字节流专用字符流:

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

尽管对象引用b属于Animal类型,但是它运行的是Dog类的move方法。

这是由于在编译阶段,只是检查参数的引用类型。

然而在运行时,Java虚拟机(JVM)指定对象的类型并且运行该对象的方法。

因此在上面的例子中,之所以能编译成功,是因为Animal类中存在move方法,然而运行时,运行的是特定对象的方法。

参数列表必须完全与被重写方法的相同;

返回类型必须完全与被重写方法的返回类型相同;

访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。

父类的成员方法只能被它的子类重写。

声明为final的方法不能被重写。
声明为static的方法不能被重写,但是能够被再次声明。

子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。

子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。

重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
构造方法不能被重写。

如果不能继承一个方法,则不能重写这个方法。

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

最常用的地方就是构造器的重载。

被重载的方法必须改变参数列表(参数个数或类型不一样);

被重载的方法可以改变返回类型;

被重载的方法可以改变访问修饰符;

被重载的方法可以声明新的或更广的检查异常;

方法能够在同一个类中或者在一个子类中被重载。

无法以返回值类型作为重载函数的区分标准。

总结

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。

(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。

(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作

多态性是对象多种表现形式的体现。

多态的优点

1. 消除类型之间的耦合关系

2. 可替换性

3. 可扩充性

4. 接口性

5. 灵活性

6. 简化性

多态存在的三个必要条件

继承

重写

父类引用指向子类对象 比如:Animal ad=new Dog();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

实例中,实例化了两个 Salary 对象:一个使用 Salary 引用 s,另一个使用 Employee 引用 e。

当调用 s.mailCheck() 时,编译器在编译时会在 Salary 类中找到 mailCheck(),执行过程 JVM 就调用 Salary 类的 mailCheck()。

因为 e 是 Employee 的引用,所以调用 e 的 mailCheck() 方法时,编译器会去 Employee 类查找 mailCheck() 方法 。

在编译的时候,编译器使用 Employee 类中的 mailCheck() 方法验证该语句, 但是在运行的时候,Java虚拟机(JVM)调用的是 Salary 类中的 mailCheck() 方法。

Java虚方法你可以理解为java里所有被overriding的方法都是virtual的,所有重写的方法都是override的。

在JVM字节码执行引擎中,方法调用会使用invokevirtual字节码指令来调用所有的虚方法。

需要注意虚方法和抽象方法并不是同一个概念

方式一:重写:

这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:Java 重写(Override)与重载(Overload)。

方式二:接口

1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。

2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看 java接口 这一章节的内容。

方式三:抽象类和抽象方法

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。

1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。

5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

java继承中对构造函数是不继承的,只是调用(隐式或显式)

在创建子类的对象时,Java虚拟机首先执行父类的构造方法,然后再执行子类的构造方法。在多级继承的情况下,将从继承树的最上层的父类开始,依次执行各个类的构造方法,这可以保证子类对象从所有直接或间接父类中继承的实例变量都被正确地初始化。

创建有参构造函数后,系统就不再有默认无参构造函数。

如果没有任何构造函数,系统会默认有一个无参构造函数。

抽象类中:

可以有构造方法;

方法可以是隐式抽象的;也可以是实现了的方法体;

成员变量可以是各种类型的;

抽象类是可以有静态代码块和静态方法;不能有声明为static的抽象方法;

构造方法,类方法(用static修饰的方法)不能声明为抽象方法。

原因:Java抽象类中不能有静态的抽象方法,可以有静态的成员方法。抽象类是不能实例化的,即不能被分配内存;而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:抽象类不能被分配内存,而static方法必须被分配内存。所以抽象类中不能有静态的抽象方法。定义抽象方法的目的是重写此方法,但如果定义成静态方法就不能被重写。

接口中:

不能有构造方法;

方法声明都是隐式抽象的public abstract方法;

接口中的成员变量只能是 public static final 类型的;

接口中不能含有静态代码块以及静态方法(用 static 修饰的方法)

接口中的方法也只能是 public abstract修饰的,不能加上static。接口是不能实例化的,即不能被分配内存,而static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了:接口不能被分配内存,而static方法必须被分配内存。所以接口中不能有静态的抽象方法。

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。

接口没有构造方法,因为接口不能实例化;

第一:集合框架常用的接口有哪些?

复杂方式存储对象是值键值映射的时候;

java集合框架就是提供一些接口和类,位于java.util包中;

Iterator(操作集合的迭代器)、Map、Collection是接口;虚线空心箭头是子接口继承父接口;长方形实现是实现类;

utilties是工具类:有Collections、Arrays;看见util就是工具类;

第二:这些接口有哪些特点?

Collection接口存储一组不唯一、无序的对象。

List接口存储一组不唯一(可重复)、有序(存储空间连续)(插入顺序)的对象;

Set接口存储一组唯一,无序的对象

Map接口存储一组键值对象,提供key到value的映射;

37.2、ArrayList(是一个可变数组)

ArrayList是连续的空间,长度可变;

LinkedList是可不连续的空间;

shift+alt+s:生成getter和setter

ctrl+shift+o或者Ctrl+1导包;

集合有了list以后,在内存中就开辟空间了;

ArrayList有个固定的长度,插入数据超过后,会自动扩充;

运行结果:

标红色的是Collection接口的方法;

clear()是清空集合;isEmpty()返回是True代表清空了;iterator()返回这个集合的迭代器;toArray()集合变成数组或者序列;

37.3、LinkedList(是一个列表)

注意:add()和addLast()的区别

eclipse调试F6是跳过方法,F5是进入放法;

注意:ArrayList再插入元素时,是插入位置的元素依次往后移;

LinkedList在插入元素时,只是插入结点位置不一样;其他不变,只是修改next和previous

LinkedList常用方法:

总结:

37.4、HashSet

java虚拟机会管理内存空间,可能划分为栈(存放平时的变量),堆(存放的是对象),方法区(和类相关的字节码数据、类中的方法)

new:生成对象;

类型 变量:是变量;

Set存放的就是对象的引用,s1、s2引用的同一个对象;所以s1和s2是重复的对象;

Set是类似于map的一个数据结构;

HashMap有个hash码,计算两个hash码,如果java和Java的hash码一样或者相近的,就会放到一个地方,同一个位置。

若不同key的hascode相同,则存储在同一个数组地址链表上,存储格式为entry(key,value)

第一、set增加位置是随机的,先加的s1还是s2不确定,总之最后添加的会覆盖掉重复的;

set接口如何判断加入对象是否已经存在呐?

采用对象的equals()方法比较两个对象是否相等,即时候指向的是同一个对象;若返回值是True,则后面的值会覆盖掉前面的值!注意:在String中equals是比较两个字符串的内容(可以是分别new的)是否一样,可能是两个引用,String类重写过equals方法,只要字符串值一样,则认为是一个对象,set就会只加一个!

注意set中没有get方法:因为set中是无序的,存放的时候是乱的,所以不能通过下标找到对应元素;

那如何实现元素输出呐?

答:可以通过增强型for来进行;

迭代器可以定位到集合里面的每一个元素:有方法hasnext(),判断有没有下一个元素---返回boolean;如果有(hasnext)下一个元素,取下一个元素就是next()方法;

iterator遍历的时候是拿元素作为一个集合去遍历;不会像是数组一样从0开始去找;找元素的集合;

运行结果为:

list获取元素的方法:

set获取元素的方法:

List和Set是Collection的子接口,注意接口可以多继承,但是没有办法实例化,

Map不是Collection的子接口;

Ctrl+shift+o是导入多个包;

Iterator迭代器,是与Collection和Map无关的一个接口

37.5 Map

Map:中的key是唯一的,无序是Set;值value可以重复,还无序,是Collection

运行结果:

迭代器是什么类型的接口?

答:Iterator类型的;接口也是一种类型,可通过接口声明接口类型的对象,只不过new的时候没有办法创建接口类的对象,因为接口没有办法实例化。接口有实现类,即通过父类类型指向子类类型对象。也叫创建了一个接口类的对象。

map中的方法Set>  entrySet():返回键值对集合,类型是Map.Entry的集合Set,如下图;

运行结果:

练习题:

解决了,取元素时,不用再强制类型转换;

所有的集合类和接口都实现了泛型;

解释:ArrayList数组以前能放Object类型的对象,现在加上泛型后只能装Student类型的对象。取数据时就不用再进行类型转换了!而Poem类型的对象是不能加到ArrayList中的。

操作空对象就会报NullpointerException,即null.say();

泛型的好处:数据添加的时候更安全;往外取数据的时候不用再类型转换;

ArrayList用泛型:

运行结果:

Map用泛型:

每个Map.Entry键值对的键类型是String,值类型是String,所以有Map.Entry,所有的键值对又是组成Set。所以有了类型Set>

运行结果为:

调用sort方法时,会根据集合里面的类型(比如是元素是:String)的自然排序规则(就是比较字母在26个里面的ASCII)去排序;

但是如果集合里面是Dog类型呐?怎么排序呐?

compareTo()的方法体就是排序规则;

对集合中的什么类型进行排序,就让该类要实现Comparable接口,去重写compartTo()方法;

运行结果:

用name来比较大小呐?

运行结果:

其中String类中compartTo()方法是:

来自慕课网:https://www.icourse163.org/learn/PKU-1001941004?tid=1450230441#/learn/content?type=detail&id=1214366030&cid=1217994056

具有含义的常量:

参考CSDN:https://blog.csdn.net/huanhuanq1209/article/details/80636730