暂时写到这里
发布记录:2021年03月25日
推荐一个基础自学网站:https://how2j.cn/
一、对象导论
对象导论对所有章节的内容进行了一个简单的介绍。具体内容从第二章开始。
1.认识第一个缩写:OOP,Object-oriented Programming
2.对象具有状态、行为和标识。
3.类描述了具有相同特性(数据元素)和行为(功能)的对象集合,类实际上就是一个数据类型。
4.认识第二个缩写:UML,Unified Modelling Language
5.聚合:组合是动态发生的。组合是has-a(拥有)关系
6.继承:基类与导出类(子类,或者称为继承类)的关系是is-a(是一个)关系
二、一切都是对象
1.数据存储的位置
存储数据的五个位置 | |||
序号 | 名称 | 位置 | 特点 |
1 | 寄存器 | 处理器内部 | ①存储速度最快,寄存器存储 ②寄存器数量有限,无法直接控制 ③其按需求分配 |
2 | 堆栈 | 通用RAM(随机访问存储器) | ①存储速度仅次于存储器,通过堆栈指针可以从处理器那里获得直接支持 ②堆栈指针向下移动,分配新内存;反之,释放内存 ③使用前提,创建程序必须知道堆栈内所有项的生命周期。失去了灵活性,java对象不存储在这里 |
3 | 堆 | 通用的内存池(位于RAM区) | ①存放java对象 ②不需要知道存储的数据的生命周期,具有分配存储的灵活性 ③缺点:存储分配和清理使用的时间需要更多 |
4 | 常量存储 | 程序代码内部或者ROM(只读存储器) | ①安全,保持数据不会被改变 |
5 | 非RAM存储 | 其它媒介的事物 | ①可以不受程序的任何控制,程序是否运行都可存在 ②基本使用例子如流对象和持久化对象 |
2.基本类型的学习
3.作用域:由花括号的位置决定,它决定了在其内定义的变量名的可见性和生命周期。
4.对象的作用域:不具备和基本类型一样的生命周期,java有一个垃圾回收器,用来监视用new创建的所有对象,并辨别那些不会再被引用的对象
5.字段(也称为数据成员,成员变量),方法(也称为成员函数),它们都是类中的元素。
6.static关键字:
作用:为某特定域分配单一存储空间,同时能够通过类名直接调用其方法
描述:static修饰的成员变量在类运行时就会执行,即分配存储空间,且仅会执行一次
static修饰的方法中不允许有this关键字,其方法可以通过类名直接调用
7.java注释简要说明,包括标签示例说明
8.通过cmd运行命令生成程序的注释文档,语法如下
javadoc -d Mydoc -author -version 类名.java
说明:Mydoc自定义文件夹的名称
类名是需要生成文档的类的名称
实现前提:在该文件的目录下运行cmd
9.编码风格说明
三、操作符
1.用一张表来显示所有的操作符
2.直接常量的习惯表示:long型,后面加L;float型,后面加F;double型,后面加D
3.进制数的表示:二进制,用0和1表示
八进制,前缀是0,后续是0-7
十进制,用0-9表示
十六进制,前缀是0x或者0X,后续是0-9或小写(或大写)的A-F
4.进制数之间的相互转换
5.窄化转换:将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型,可能面临信息丢失的危险。如把long型转成int型时。
6.拓展转换:与窄化转换相反,但是它不会造成任何信息的丢失。
7.类型转换语法:(转换的类型名称)转换的值。该转换方式下,浮点型转成整型时是直接去掉小数部分。
8.注意的问题:在类型转换中,有可能会造成结果溢出,但是这个不会报出异常,需要特别注意。
9.补充举例说明移位操作符的计算方式
package com.study.thinking.in.java.part3;
public class PartDemo3 {
public static void main(String[] args) {
// 以下测试中,对于int型都是低5位数有效,long型低6位有效
// 左移在低位均是补0
int a = 1;
// 说明:最高位0始终不变
// 正数1的二进制数表示为1
System.out.println(Integer.toBinaryString(a));
a <<= 5;
// 左移5位低位补0,结果就是100000,对应的十进制数就是32(即当前的a值)
System.out.println(Integer.toBinaryString(a));
int a1 = -1;
// 说明:最高位1始终不变
// 步1:二进制:1000 0000 0000 0000 0000 0000 0000 0001
// 步2:二进制补码:1111 1111 1111 1111 1111 1111 1111 1110
// 步3:二进制补码加1:1111 1111 1111 1111 1111 1111 1111 1111
System.out.println(Integer.toBinaryString(a1));
a1 <<= 5;
// 步4:左移之后变为(低位补0):1111 1111 1111 1111 1111 1111 1110 0000
// 步5:二进制补码:1000 0000 0000 0000 0000 0000 0001 1111
// 步6:二进制补码加1:1000 0000 0000 0000 0000 0000 0010 0000,结果值就是-32
System.out.println(Integer.toBinaryString(a1));
int b = 1;
b >>= 5;
// 说明:最高位0始终不变
// 步1:二进制:0000 0000 0000 0000 0000 0000 0000 0001
// 步2:右移之后变为(整数最高位补0):0000 0000 0000 0000 0000 0000 0000 0000(舍弃步3的最后5位),结果值就是-1
System.out.println(Integer.toBinaryString(b));
int c = -1;
c >>= 5;
// 说明:最高位1始终不变
// 步1:二进制:1000 0000 0000 0000 0000 0000 0000 0001
// 步2:二进制补码:1111 1111 1111 1111 1111 1111 1111 1110
// 步3:二进制补码加1:1111 1111 1111 1111 1111 1111 1111 1111
// 步4:右移之后变为(负数最高位补1):1111 1111 1111 1111 1111 1111 111(舍弃步3的最后5位)
// 步5:二进制补码:1000 0000 0000 0000 0000 0000 000
// 步6:二进制补码加1:1000 0000 0000 0000 0000 0000 001,结果值就是-1
System.out.println(Integer.toBinaryString(c));
// 无符号位则均是补0
int d = -1;
d >>>= 5;
// 步1:二进制:1000 0000 0000 0000 0000 0000 0000 0001
// 步2:二进制补码:1111 1111 1111 1111 1111 1111 1111 1110
// 步3:二进制补码加1:1111 1111 1111 1111 1111 1111 1111 1111
// 步4:右移之后变为(最高位补0):0000 0111 1111 1111 1111 1111 111(舍弃步3的最后5位)
// 步5:二进制补码:1111 1000 0000 0000 0000 0000 000
// 步6:二进制补码加1:111 1100 0000 0000 0000 0000 0001,结果值就是134217727
System.out.println(Integer.toBinaryString(d));
// 无符号位则均是补0
int e = 1;
e >>>= 5;
// 步1:二进制:0000 0000 0000 0000 0000 0000 0000 0001
// 步2:右移之后变为(最高位补0):0000 0000 0000 0000 0000 0000 000(舍弃步3的最后5位),结果值就是0
System.out.println(Integer.toBinaryString(e));
//总结:左右移位时,负整数需要先换成补码加1再进行移位,移位之后,再换成补码加1即得到最后的结果。而正整数直接二进制移位即可
}
}
==================================================================================================================================================================================
a = 1 二进制数: 1
a = 1 左移位5位: 100000
a1 = -1 二进制数(补码加1的形式): 11111111111111111111111111111111
a1 = -1 左移位5位: 11111111111111111111111111100000
c = 1 有符号右移位5位: 0
c = -1 有符号右移位5位: 11111111111111111111111111111111
d = -1 无符号右移位5位: 111111111111111111111111111
e = 1 无符号右移位5位: 0
四、控制执行流程
1.条件语句,根据条件执行相应的语句
001.if语句语法
if(Boolean-expression)
statement;
002.if-else语句语法
if(Boolean-expression)
statement;
else
statement;
003.switch语句语法
switch(integral-selector){
case integral-value1:
statement;
break;
case integral-value2:
statement;
break;
case integral-value3:
statement;
break;
// ...
default:
statement;
}
2.迭代语句:控制循环的语句。主要有以下三种:
(1)while循环,语法:
while(Boolean-expression)
statement;
(2)do...while循环,语法:
do
statement;
while(Boolean-expression)
(3)for循环,语法:
for(initialization;Boolean-expression;step)
statement;
3.无限循环的两种表达方式
(1)while(true)statement;
(2)for(;;) statement;
4.遍历数组的两种方式
001.for循环遍历,语法:
int[] list = new int[10];
for(int i = 0; i < list.length; i++){
System.out.println(list[i]);
}
002.Foreach循环遍历,语法:
int[] list = new int[10];
for(int i: list){
System.out.println(i);
}
5.结束控制语句的几种方法
(1)正常执行完所有语句
(2)可以使用break,continue,return结束语句的执行,三者区别如下
001.break,可用于条件语句和循环语句中,表示结束当前条件语句的执行或者循环语句的执行
002.continue,只可用于循环语句中,表示跳过本次循环,执行下一次循环
003.return,均可用,表示结束该方法体的执行,在最接近的同一个大括号中,return之后不允许再有执行语句
错误示例如下:
// 这是一个错误的例子
for(int i = 0;i<10;i++{
if(i == 3){
return;
System.out.println(i);
}
}
6.多层循环中break,continue,return的用处:
// 三层嵌套示例
label1:
for(int i=0;i < 3;i++) {
if(i == 2)
break label1;// 结束标记标签label1以下的所有循环
label2:
for(int j = 0; j < 3; j ++) {
if(j == 1)
continue label1; // 跳出j循环,直接执行i++
System.out.println("===============分割线 i ="+i+" j = "+ j+" =================");
for(int k = 0; k < 3; k ++) {
if(k == 0)
continue; // 跳过k == 0,执行k == 1
if(k == 2)
break; // 退出k循环
// 下面打印语句只执行了一次,即 k == 1时
System.out.println(" k == "+k);
}
}
}
===================测试结果=====================
===============分割线 i =0 j = 0 =================
k == 1
===============分割线 i =1 j = 0 =================
k == 1
总结:
01.break,结束一个循环体,break label,结束一个标签内的所有循环体;
02.continue,跳过一次循环,continue label,跳到指定标签开始下一次循环;
03.return,结束方法体。
7.逗号操作符在循环语句中的作用:通过使用逗号操作符,在for循环语句中定义多个变量,但是这有一个前提:变量的类型应该是相同的。
8.学习示例汇总如下:
Scanner scanner = new Scanner(System.in);
// 练习1:打印1到100的整数
for(int i = 1; i< 101; i++){
System.out.println(i);
}
// 练习2:产生25个随机整数,从第二个开始,和前一个比较大小,分别打印出来
int[] list = new int[25];
for (int i = 0; i < list.length; i++) {
// Math.random()产生0 - 1的随机浮点数
list[i] = (int)(Math.random()*26);
// 从第2个开始和前一个比较
if(i > 0){
if(list[i] > list[i-1])
System.out.println(list[i]+" > "+list[i-1]);
else
System.out.println(list[i]+" <= "+list[i-1]);
}
}
// 练习3:两个嵌套for循环和取余方式检测输入的整数是否是素数(素数是只能被自身和1整除)
label:
for(int i = 0; i < 10; i++){
System.out.println("输入一个整数:");
int num = scanner.nextInt();
for(int j = 2; j < num; j++){
if(num % i == 0){
System.out.println(num+"这个数不是素数");
break label;// 如果输入的数字不是素数,结束执行
}
}
}
//练习4:斐波那契数列,从第三个数开始,均是前两个数之和,输入一个整数,输出斐波那契数列的参数个数:如输入5,就有5个数
System.out.println("输入一个整数:");
int num = scanner.nextInt();
System.out.println("斐波那契数列为:");
int firstNum = 1;
int secondNum = 1;
for(int i = 0;i < num; i++){
if(i < 2){
System.out.print(firstNum + "\t");
} else{
int threeNum = firstNum + secondNum;
System.out.print(threeNum + "\t");
firstNum = secondNum;
secondNum = threeNum;
}
}
// 练习5:4位数字的所有吸血鬼数字(位数为偶数的数字,如2,4,6位数数;同时组成的数字两两组合相乘可以得到该数)
for(int i = 1000; i< 10000; i++){
// 剔除后面两个是0的情况
if(i % 100 != 0){
// 转成字符串
String str = String.valueOf(i);
Label:
for(int k = 11; k < 100; k++){
int num = i % k;
// 对整除结果进行判断
if(num == 0){
// 获取对应的数字并转成字符串
int value = i / k;
String[] strs = new String[4];
strs[0] = String.valueOf(k % 10);
strs[1] = String.valueOf(k / 10);
strs[2] = String.valueOf(value % 10);
strs[3] = String.valueOf(value / 10);
// 组合成字符串,如果相等即找到了,如果不等,则继续
for (int j = 0; j < strs.length; j++) {
for (int m = 0; m < strs.length; m++) {
if(j != m){
for (int m1 = 0; m1 < strs.length; m1++) {
if(m != m1 && j != m1){
for (int m2 = 0; m2 < strs.length; m2++) {
if(m2 != m && j != m2 && m2 !=m1){
String res = strs[j]+strs[m]+strs[m1]+strs[m2];
if(res.equals(str)){
//System.out.println("res = "+res + " and str = "+str);
System.out.println(i+"是吸血鬼数字,"+i +" = "+k+"*"+value);
break Label;
}
}
}
}
}
}
}
}
}
}
}
}
五、初始化与清理
1.类的基础知识
A.构造器:确保对象的创建能够被初始化。包括了两类构造器
01.无参构造器(默认构造器,如果编程过程中不写构造器,系统默认创建一个无参构造器)
02.有参构造器(也可以理解为构造器的重载)
注意:构造器的名称应该和类名完全一致,构造器也是一种方法,称为构造方法。
B.方法的重载:方法名相同,但是参数列表不完全相同,这样的方法称为方法的重载。
注意点:01.在方法名相同的情况下,重载的参数列表一样,但是顺序不同也是方法的重载,但是在编程过程中不建议这样创建重载方法
02.根据返回值类型来区分方法重载是行不通的,因为有时我们的需求不需要使用到返回值,而只是方法的执行过程
C.this关键字
01.使用范围:只能在非静态方法(包括构造方法)内调用
02.使用建议:在同一个类中,非静态方法中调用其它方法,不需要写this
03.构造器说明:this在构造器中指代当前对象,通过它可以直接调用其它构造方法,但是只能调用一次构造方法且必须写在第一行(默认情况下调用父类的默认构造方法,一般不写出来)
D.static关键字
01.static方法的内部不能调用非静态的方法,反过来可以。
02.static修饰的方法或变量,可以通过类名直接访问
03.static修饰的方法中全局变量必须是static修饰的
04.static不能用于局部变量的修饰
package com.study.thinking.in.java.part5;
public class Student {
static int id;
String sudentID;
// 无参构造方法(无参构造器),即默认构造器,如果隐藏不写,并且不重写构造器,那么编译时,自动创建构造器,如果已经存在重写的构造器,将不再创建无参构造方法
public Student(){
// 下面是父类的默认构造方法,如果在该构造器中没有调用其它构造方法,它默认存在,并且可以忽略不写出来;如果已经写出,下面将不能再用this调用构造方法
// super();
// this指代student对象本身,它有一个重载的构造方法,所以以下可以直接使用
this("preston",20);
// 错误演示:this调用构造方法只能一次且必须写在第一行
// this("David",18);
// this指代student对象本身,对它的id值进行初始化
this.sudentID = "2021001";
System.out.println("没有指明名字和年龄的学生");
}
// 有参构造方法(有参构造器),名称与类名一致,当写了有参构造方法,如果不写无参构造方法,将无法通过无参构造创建对象
public Student(String name,int age){
System.out.println("学生姓名是:"+name+",学生年龄是:"+age);
}
public static void main(String[] args) {
// 在static修饰的方法中,不能使用this,并且不能调用非静态的方法,以下是错误示例
// subject("English");
Student student = new Student();
// static修饰的方法访问static修饰的方法
describeStudentId();
}
public static void describeStudentId(){
System.out.println(id+"是学生编号");
}
// 方法:科目名称
public void subject(String name){
System.out.println(name+"科");
}
// 方法重载1:科目分数
public void subject(int score){
System.out.println(score+"分");
}
// 方法重载2:科目名称和分数
public void subject(String name,int score){
// 调用同类中的方法,不需要写this
// this.subject("English");可以省略this
subject("English");
System.out.println(name+"科 "+score+"分");
}
// 错误范例:与上面的方法冲突,不是方法的重载
// public int subject(String name,int score){ }
}
class Test5{
public static void main(String[] args) {
// Student重写了构造方法,不写无参构造方法,无法在通过无参构造创建对象,以下内容报错
//Student student = new Student();
// id被static修饰可以直接通过类名访问
Student.id = 5;
// 方法被static修饰可以直接通过类名访问
Student.describeStudentId();
}
}
2.java中对象垃圾回收的三个知识要点:
01.对象可能不被垃圾回收
02.垃圾回收并不等于“折构”
03.垃圾回收只与内存有关
注:java虚拟机在并未面临内存耗尽的情况下,它是不会浪费时间去执行垃圾回收以恢复内存的。
3.几种垃圾回收技术的初步认识
01.引用计数,是一种简单但速度很慢的垃圾回收技术。每一个对象都含有一个引用计数器,有引用接至对象时,引用计数加1,离开或被置为null时,减1。垃圾回收期会在含有全部对象的列表上进行遍历,当发现某个对象的引用计数为0时,就释放其占用的空间。
缺陷:如果对象之间存在循环引用,可能出现“对象应该被回收,但引用计数却不为零”。
02.自适应的垃圾回收技术,关键词:分代的、停止-复制、标记-清扫。
4.初始化:成员初始化、指定初始化、构造器初始化、静态数据的初始化、显示的静态初始化、非静态实例初始化、数组初始化
总结:初始化是在编译时就进行的,它会将所有的初始化内容进行初始化,无法进行初始化的将会报出编译时异常
01.成员变量的初始化,基本类型会进行默认赋值
02.指定初始化是直接给予赋值操作
03.构造器初始化,构造器的内容初始化顺序是根据执行构造方法的先后顺序决定
04.静态数据的初始化是发生在类运行时,是最先进行初始化的
05.显示的静态初始化就是构造代码块的初始化
06.非静态实例初始化就是对象的初始化
07.数组初始化,数组使用前必须进行初始化
08.可变参数:参数个数或类型未知时使用。当知道类型,未知个数,则应该指明类型,否则使用Object。表示方法示例:
public void study(Object...args){
// 方法体
}
5.枚举类型:关键字enum修饰类名,常用作具有固定选择,以坦克大战方向举例如下:
package com.study.thinking.in.java.part5;
// 枚举类:四个方向
public enum Direction {
// 左右上下四个方向
LEFT,RIGHT,UP,DOWN
}
class Tank{
public static void main(String[] args) {
new Tank().moveDirection(Direction.DOWN);
}
private void moveDirection(Direction direction){
// 判断移动方向
switch (direction){
case UP:
System.out.println("向上运动");
break;
case DOWN:
System.out.println("向下运动");
break;
case RIGHT:
System.out.println("向右运动");
break;
case LEFT:
System.out.println("向左运动");
break;
}
}
}
六、访问权限控制
1.包名:必须是独一无二的(根据域名创建),它是类库单元。写在非注释第一行
2.引入包:通过关键字import+包名(全局名称)导入使用,写在包名下面
3.四种访问权限
七、复用类(两种方式实现:一个是组合,一个是继承)
1.组合语法:(组合:就是在新类中通过创建已有类对象,实现对已有类的使用,通俗的讲就是创建类的实例对象,从而实现对类的功能的调用),如下例子
/**
* 组合类使用范例
*/
public class CombineClassDemo {
private String message;
private OldCombineClass oldCombineClass = new OldCombineClass();
public String toString(){
return "message = " + message+",\t"+
"oldCombineClass = "+oldCombineClass;
}
// 测试:通过创建对象实现对类的使用
public static void main(String[] args) {
CombineClassDemo combineClassDemo = new CombineClassDemo();
System.out.println(combineClassDemo);
}
}
class OldCombineClass{
private String message;
public OldCombineClass(){
System.out.println("OldCombineClass()");
message = "Constructed";
}
public String toString(){
return message;
}
}
==============================输出结果=======================================
OldCombineClass()
message = null, oldCombineClass = Constructed
2.继承语法:(继承:根据已有的类创建新类,对于新类只需将拓展的新方法实现即可,对于已有方法可以直接调用(在默认修饰符均为公共的情况下)),如下例子
继承类:称为导出类,也称为子类(自己习惯称为子类)
被继承类:称为基类,也称为父类(自己习惯称为子类)
/**
* 继承使用范例
* 继承类,即导出类
*/
public class ExtendsClassDemo extends ExtendsClass{
// 测试:通过继承实现对类的使用
public static void main(String[] args) {
// 默认调用基类的toString()方法
ExtendsClassDemo extendsClassDemo = new ExtendsClassDemo();
System.out.println(extendsClassDemo);
}
}
// 被继承类,即基类
class ExtendsClass{
private String message;
public ExtendsClass(){
System.out.println("OldCombineClass()");
message = "Constructed";
}
public String toString(){
return message;
}
}
===========================================输出结果===================================
OldCombineClass()
Constructed
3.基类(父类)的初始化:实行原则是:从最顶级的父类开始、直至导出类(即子类)依次初始化,下面这个范例可以很好地体现出来
说明:01.默认情况下,在调用子类的构造方法创建子类对象时,均会调用基类的无参构造方法进行基类的初始化,该语句是super(),如果写出来要求必须写在第一行,且同一个调用的构造方法中,只能写一次,无论是否有无参数
02.如果在调用子类的构造方法中给父类进行传参,如例子中的super(str)则要求基类中存在对应的有参构造,否则将报错
03.在默认情况下,类会自动创建一个无参构造方法,该方法没有任何具体内容;但是当创建的类中已有有参构造方法,无参构造方法将不会默认创建,所以需要使用的话,需要在创建类时手动创建
总结:01.基类的无参构造方法在默认情况下均会被调用
02.在创建基类时,如果有有参构造方法存在,应该写上无参构造方法
// 导出类,即子类
public class InitClassDemo extends Person{
/**
* 同一个类中,不同的构造方法之间不能相互调用,如该例中有参构造和无参构造不能相互调用
*
* @param str 字符串
*/
public InitClassDemo(String str){
// 初始化基类的有参构造必须写出来,super("")构造方法必须写在调用的构造方法中的第一行,而且只能写在构造方法中
super(str);
System.out.println(str+"这是人类中的一员,名字叫preston2");
}
public InitClassDemo(){
// super()是默认存在的,如果要写出来,必须写在构造方法的第一行,而且只能写在构造方法中
// super();
System.out.println("这是人类中的一员,名字叫preston");
System.out.println("-------------------------分割线------------------------");
// 创建对象是允许的
new InitClassDemo("有参构造:");
// 调用构造方法是错误的
// InitClassDemo("");
}
public static void main(String[] args) {
// 无参构造方法创建导出类对象,基类实现初始化,这里创建的是匿名对象
new InitClassDemo();
}
}
// 既是导出类,也是基类
class Person extends Humen{
public Person(){
System.out.println("这是人类中的一员");
}
public Person(String str){
super(str);
System.out.println(str+"这是人类中的一员");
}
}
// 基类
class Humen{
public Humen(){
System.out.println("这是人类");
}
public Humen(String str){
System.out.println(str+"这是人类22");
}
}
==========================测试结果===============================
这是人类
这是人类中的一员
这是人类中的一员,名字叫preston
-------------------------分割线------------------------
有参构造:这是人类22
有参构造:这是人类中的一员
有参构造:这是人类中的一员,名字叫preston2
4.代理的语法:(略,也是可以实现对一个类的各种方法使用)
现在java可以通过Proxy实现,基础知识应用到的是反射,后面章节学习到再写。
也有工具可以直接生成,书上说JetBrains Idea IDE可以自动生成
上述的三种使用复用类的方法通常是结合使用的。
5.组合与继承的选择使用原则
01.使用继承:两个类的关系是(is-a关系),即该类是另一个类的延伸或拓展,是一种从属关系,形象比喻如:汽车和交通工具的关系
02.使用组合:两个类的关系是(has-a关系),即该类和另一个类存在相同部分,是一种交集关系。形象比喻如:汽车轮子和汽车的关系
6.向上转型:由导出类转成基类,即子类转成父类。因为在继承图上是向上移动的,所以称为向上转型。
7.final关键字
01.修饰数据,如果是变量,其数值恒定不变,称为常量;如果是对象,其指向的对象恒定(仅是指定引用的对象恒定,但是对象的内容是可以改变的)
02.空白final,可以先定义,但是在初始化时,构造函数中必须给其进行初始化;注意,如果使用static修饰final则不行(因为static修饰的变量先于构造方法执行),如下
03.修饰参数,参数将不允许修改,但是可以使用
public class ExampleFinalDemo {
private final int i;
// 报错,未进行初始化
//private static final int j;
public ExampleFinalDemo(){
i = 1;
System.out.println("i = "+i);
print(5);
}
public void print(final int num){
System.out.println("num = "+num);
// 报错,提示不能修改
// num = num+2;
// System.out.println("num == "+num);
}
public static void main(String[] args) {
new ExampleFinalDemo();
}
}
04.final修饰的方法不能被子类重写
05.final修饰的类不能被继承
8.类的初始化顺序
01.加载类时,优先初始化父类中的静态变量和静态代码块。其中静态变量和静态代码块的执行顺序是按语句的先后顺序依次执行
02.其次初始化子类中的静态变量和静态代码块。其中静态变量和静态代码块的执行顺序是按语句的先后顺序依次执行
03.然后初始化父类中的其它变量和代码块,按先后顺序依次执行,然后执行父类构造方法中的其它代码
04.再然后初始化子类中的其它变量和代码块,按先后顺序依次执行,然后执行子类构造方法中的其它代码
运用代码演示如下:
public class ExampleInitDemo extends ExampleClass {
private ExampleTest1 test1 = new ExampleTest1("执行顺序09:");
static {
new ExampleTest1("执行顺序03:");
}
private static ExampleTest1 test2 = new ExampleTest1("执行顺序04:");
{
new ExampleTest1("执行顺序10:");
}
static {
new ExampleTest1("执行顺序05:");
}
{
new ExampleTest1("执行顺序11:");
}
public ExampleInitDemo(){
new ExampleTest1("执行顺序12:");
}
public static void main(String[] args) {
new ExampleInitDemo();
}
}
class ExampleClass{
private ExampleTest1 test1 = new ExampleTest1("执行顺序06:");
private static ExampleTest1 test2 = new ExampleTest1("执行顺序01:");
static {
new ExampleTest1("执行顺序02:");
}
{
new ExampleTest1("执行顺序07:");
}
public ExampleClass(){
new ExampleTest1("执行顺序08:");
}
}
class ExampleTest1{
public ExampleTest1(String str){
System.out.println(str+"测试用例进行初始化了");
}
}
===================================演示结果============================================
执行顺序01:测试用例进行初始化了
执行顺序02:测试用例进行初始化了
执行顺序03:测试用例进行初始化了
执行顺序04:测试用例进行初始化了
执行顺序05:测试用例进行初始化了
执行顺序06:测试用例进行初始化了
执行顺序07:测试用例进行初始化了
执行顺序08:测试用例进行初始化了
执行顺序09:测试用例进行初始化了
执行顺序10:测试用例进行初始化了
执行顺序11:测试用例进行初始化了
执行顺序12:测试用例进行初始化了
八、多态
1.
二十二、图形用户化界面
1.视窗(JFrame)
01.视窗的创建及其基础设计:具有如下两种方式实现视窗界面的显示
/**
* 普通写法显示视窗
*/
public class JFrameDemo {
public static void main(String[] args) {
// 视窗的对象创建
JFrame frame = new JFrame();
// 视窗的标题设置
frame.setTitle("测试用例");
// 组件的名字(图形显示并未观察到)
frame.setName("这是视窗");
// 视窗的尺寸设置
frame.setSize(1000,800);
// 视窗的在屏幕出现的位置设置
frame.setLocation(new Point(100,50));
// 关闭视窗时的操作,JFrame.EXIT_ON_CLOSE表示视窗会关闭,同时推出程序,JFrame.NORMAL表示正常显示,不会关闭,JFrame.DISPOSE_ON_CLOSE表示会关闭当前视窗
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// 显示视窗,true显示,可见,false不显示,不可见
frame.setVisible(true);
}
}
/**
* 继承方式显示视窗
*/
class MyJFrame extends JFrame{
public static void main(String[] args) {
new MyJFrame();
}
public MyJFrame(){
setTitle("视窗标题");
setSize(1000,800);
// 窗口不可以放大
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}