- 1 面向对象和面向过程
- 2 类和对象
- 3 成员变量和局部变量
- 4 封装
- 5 pojo(待修订)
- 6 this关键字
- 7 构造方法
- 8 对象的初始化过程
- 9 练习
- 10 static关键字
- 11 文档注释
- 12 main方法
- 13 Math类
- 14 代码块
- 15 作业
面向过程:
面向着具体的每一个步骤,把每一个步骤完成,相互调用,完成需求。
典型语言:C
面向功能(过程)的
函数(方法)是程序的基本单位
公式:程序=算法+数据结构
面向对象:
根据不同的功能,进行不同的封装,功能类似的封装在一起。
典型语言: Java, C++...
面向对象的
类是程序的基本单位
方法被封装在类中
数据被封装在类中
公式:程序=对象+消息 (消息通过.运算符实现)
特点:
更符合人类的思维习惯
将复杂的事情简单化
程序员从执行者变成了指挥者
举例:
吃饭
面向过程:去菜市场 --> 挑菜 --> 讨价还价 --> 摘菜 --> 洗菜 --> 切菜 --> 炒菜 -- > 吃饭 (过程, 动词)
面向对象:下馆子 --> 叫服务员(点菜) --> 厨师(炒菜) --> 叫服务员(上菜) --> 吃饭 (对象, 名词)
洗衣服
面向过程:倒水 --> 加洗衣粉 --> 浸泡半小时 --> 搓20分钟 --> 洗涤 --> 拧干 --> 晾衣服
面向对象:放入洗衣机 --> 加洗衣粉 --> 洗衣机(洗衣服) --> 晾衣服
专业的事情交给专业的人做。在Java中,万事万物皆对象。
**练习:**把大象装进冰箱
a.面向过程:
打开冰箱门
把大象放进冰箱
关上冰箱门
b.面向对象:
A:首先分析有哪些类
冰箱
大象
Demo (测试类)
B:接着分析每个类应该有什么
冰箱:开门, 关门
大象:进入
Demo: main
C:最后分析类与类的关系
// b.面向对象
class Fridge {
open();
close();
}
class Elephant {
in(Fridge fridge);
}
class Demo {
public static void main(String[] args) {
调用Fridge的open();
调用Elephant的in();
调用Fridge的close();
}
}
public class Demo1 {
public static void main(String[] args) {
// a.面向过程
open(); // 打开冰箱门
in(); // 把大象放进冰箱
close(); // 关闭冰箱门
// b.面向对象的实现见上面的伪代码
}
public static void open() {
System.out.println("打开冰箱门");
}
public static void in() {
System.out.println("把大象放进冰箱");
}
public static void close() {
System.out.println("关闭冰箱门");
}
}
2 类和对象
客观世界的组成:
物体;
物体之间的相互关系。
物体:
物体是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。
一个物体由一组属性和操作(功能)组成
举例:
小花猫
属性:两只耳朵, 四条腿, 颜色, 大小, 尾巴的长度...(静态的东西)
行为:喵喵喵的叫, 能撒娇卖萌, 能捉老鼠...(动态的东西)
汽车:
属性:品牌, 价格, 型号, 颜色, 排气量...
行为:启动, 加速, 刹车, 闪灯, 鸣笛, 转向...
类:
类是个抽象的概念, 是同种物体的集合与抽象。
举例:
类:学生
物体:班长
代码世界:
类:是一组相关的属性和行为的集合
对象:是该类事物的具体体现
面向对象程序设计的重点是类的设计,而不是对象的设计。
如何设计一个类?
现实中的事物
属性 身高,体重
行为 学习,吃饭
Java中用class也是如此
成员变量 类比事物的属性
成员方法 类比事物的行为
成员变量 和以前定义变量是一样的,只不过位置发生了改变。在类中,方法外。
成员方法 和以前定义方法是一样的,只不过把static去掉,后面在详细讲解static的作用。
**练习:**创建一个学生(Student)类,并测试。
Student:
public class Student {
// 成员变量
int id;
String name;
int age;
String gender;
// 成员方法
public void study() {
System.out.println("good good study, day day up!");
}
public void eat() {
System.out.println("学习饿了,要吃小龙虾");
}
public void sleep() {
System.out.println("学习累了,要休息一会儿~");
}
public void doHomework() {
System.out.println("我爱写作业");
}
}
StudentDemo:
public class StudentDemo {
// 公式:程序=对象+消息
// 消息通过.(访问操作符)来体现
public static void main(String[] args) {
// 创建对象
Student s1 = new Student();
// 访问属性
s1.id = 9527;
s1.name = "华安";
s1.age = 28;
s1.gender = "male";
System.out.println(s1.id); // 9527
System.out.println(s1.name); // 华安
System.out.println(s1.age); // 28
System.out.println(s1.gender); // male
// 再创建一个对象
Student s2 = new Student();
// 访问属性
s2.id = 10001;
s2.name = "马化腾";
s2.age = 45;
s2.gender = "male";
System.out.println(s2.id); // 10001
System.out.println(s2.name); // 马化腾
System.out.println(s2.age); // 45
System.out.println(s2.gender); // male
// 创建第三个对象,第三个对象直接执行s1
Student s3 = s1;
s3.name = "唐伯虎";
s3.age = 38;
System.out.println(s1.id); // 9527
System.out.println(s1.name); // 唐伯虎
System.out.println(s1.age); // 38
System.out.println(s1.gender); // male
}
}
对象创建过程的内存图分析:
(1)一个对象的内存图分析
(2)三个对象的内存图分析
总结:JVM内存模型
(1)栈:存放局部变量+方法的形参。
(2)堆:new出来的东西。
(3)方法区:静态的东西,以及类的字节码信息。
(4)本地方法栈:与native相关的东西,用C/C++编写的系统代码。
(5)程序计数器:字节码行号指示器,记录字节码文件执行到什么地方。
注意:在堆中创建的每一个对象,它们都有各自属性,因为每一个对象的属性值不同,但是同一个类的每一个对象的方法都是相同的,所以堆中的对象会存放这个类的方法的引用,当对象访问这个方法时,会通过堆中方法的引用,访问方法区中该方法具体的代码。
3 成员变量和局部变量成员变量和局部变量的区别
a.在内存中位置不同
局部变量: 栈
成员变量:堆
b.初始化值不同
局部变量: 没有默认值, 没有初始化,就不能使用。
成员变量:有默认值。
byte, short, int, long 0
float, double 0.0
char 'u0000'
boolean false
引用类型 null
c.在类中位置不同
局部变量: 方法内存或者方法声明上
成员变量:类中,方法外
d.生命周期不同
局部变量: 随着方法的入栈而开始,随着方法的出栈而消亡
成员变量:随着对象的创建而开始, 随着对象的死亡而消亡
Demo:
public class Demo {
public int getSum(int a, int b) {
return a + b; // a, b是局部变量
}
}
DemoTest:
public class DemoTest {
public static void main(String[] args) {
Demo demo = new Demo();
int sum = demo.getSum(10, 20);
System.out.println("sum = " + sum); // 30
}
}
匿名对象:
就是没有名字的对象,是对象的一种简化表示形式。
匿名对象的两种使用情况
对象仅仅使用一次的时候;
作为实际参数传递;
Student:
public class Student {
public void show() {
System.out.println("Student show");
}
}
StudentDemo:
public class StudentDemo {
public void method(Student s) {
s.show();
}
}
StudentTest:
public class StudentTest {
public static void main(String[] args) {
StudentDemo sd = new StudentDemo();
Student s = new Student();
sd.method(s); // Student show
sd.method(new Student()); // Student show // 匿名对象
// 上面的代码可以写成下面形式
new StudentDemo().method(new Student()); // Student show // 匿名对象
}
}
4 封装
封装(encapsulation)
封装是一种信息隐藏技术。
好处:
a. 隐藏类的实现细节,实现了信息的隐藏及安全性;
b. 提高了程序的模块化,且易于维护;
c. 保证了数据的安全和系统的严密性;
d. 将类的设计者和类的使用者分开。
封装的技术包括:包, 类, 方法, 访问权限修饰符。
private:
私有的。是一种访问权限修饰符。
被private修饰的成员变量或者成员方法只能在本类进行访问.
最常见的用法:
把成员变量用private修饰
然后提供getXxx()/setXxx()方法 getter & setter
Student:
public class Student {
String name;
private int age; // 封装
public void study() {
System.out.println("好好学习,天天向上");
}
public void setAge(int a) {
// 数据校验
if (a < 0) {
System.out.println("年龄不能为负数");
return;
}
if (a > 120) {
System.out.println("年龄不能超过120岁");
return;
}
// 下面的代码都是正常数据
age = a;
}
public int getAge() {
return age;
}
}
EncapsulationDemo:
public class EncapsulationDemo {
public static void main(String[] args) {
Student s = new Student();
s.name = "华安"; // 没有private修饰,没有封装,可以访问。
// s.age = -28; // private修饰,封装,在其它类中不能访问。
s.setAge(38);
System.out.println(s.name); // 华安
System.out.println(s.getAge()); // 38
}
}
5 pojo(待修订)
pojo = plain old java object, 又老又丑的Java对象。
Student:
public class Student {
// 成员变量
private String name;
private int age;
// getter & setter
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
// 成员方法
public void study() {
System.out.println("好好学习,天天向上");
}
}
StudentTest:
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
s.setName("刘亦菲");
s.setAge(16);
System.out.println(s.getName()); // 刘亦菲
System.out.println(s.getAge()); // 16
}
}
如果将Student类的两个setter方法修改成下面的形式,则StudentTest类中main方法运行的结果是:null, 0。因为没有完成set,属性的值是堆上的默认值。
public void setName(String name) {
name = name; // 两个name都是形参的name,局部变量隐藏了成员变量。
}
public void setAge(int age) {
age = age; // 两个age都是形参的age,局部变量隐藏了成员变量。
}
6 this关键字
this:
a.代表当前对象的引用
记住:方法被哪个对象调用,this就代表那个对象。
b.内存空间标识(和super一样)
什么时候使用this:
a.局部变量隐藏成员变量,即在pojo中的setter方法中使用this。
b.其它用法和super一起讲解。
Student:
// 本例就是this的第一种用法,解决局部变量隐藏成员变量问题。
public class Student {
// 成员变量
private String name;
private int age;
// getter & setter
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
// 成员方法
public void study() {
System.out.println("好好学习,天天向上");
}
}
ThisDemo:
public class ThisDemo {
public static void main(String[] args) {
Student s = new Student();
s.setName("刘亦菲");
s.setAge(16);
System.out.println(s.getName()); // 刘亦菲
System.out.println(s.getAge()); // 16
}
}
上述代码的内存图分析:
7 构造方法构造方法:
作用:给对象的数据进行初始化。
格式:
方法名与类名相同;
没有返回值类型,连void都没有。
注意事项:
a. 如果没写构造方法,系统会提供无参构造方法(默认的构造方法)。
b. 如果提供了构造方法, 系统将不再提供无参的构造方法。(建议: 自己写一个无参的构造方法。在Spring中,有时通过反射调用无参构造方法,如果不提供,则报错。)
c. 构造方法也是可以重载的。但是构造方法不能递归,因为没有返回值,不能使用return,即不能结束递归,所以构造方法递归时会出现栈溢出。
Student:
// 标准的pojo
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 成员方法
public void study() {
System.out.println("好好学习,天天向上");
}
public void show() {
System.out.println("Student{name=" + name + ", age=" + age + "}");
}
}
StudentTest:
public class StudentTest {
public static void main(String[] args) {
Student s = new Student(); // 无参构造方法
s.setName("Henson_z");
s.setAge(18);
System.out.println(s.getName()); // Henson_z
System.out.println(s.getAge()); // 18
s.show(); // Student{name=Henson_z, age=18}
Student s2 = new Student("刘亦菲", 16); // 有参构造方法
s2.show(); // Student{name=刘亦菲, age=16}
}
}
8 对象的初始化过程
对象的初始化过程见下图:
**总结:**默认初始化 → rightarrow → 显示初始化 → rightarrow → 构造方法,构造方法是最后执行的。
Student:
public class Student {
private String name = "Henson_z"; // 显示初始化
private int age = 18; // 显示初始化
// 无参构造方法
public Student() {
show();
System.out.println("无参构造方法");
}
// 有参构造方法
public Student(String name, int age) {
show();
System.out.println("有参构造方法");
this.name = name;
this.age = age;
show();
}
// setter & getter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show() {
System.out.println("Student{name=" + name + ", age=" + age + "}" );
}
}
StudentTest:
public class StudentTest {
public static void main(String[] args) {
Student s1 = new Student(); // 调用无参构造方法
s1.setName("贺志鹏");
s1.setAge(28);
s1.show();
System.out.println("--------------------------------");
Student s = new Student("刘亦菲", 16); // 调用有参构造方法
}
}
9 练习
练习一:定义一个类Demo, 其中定义一个求两个数据之和的方法,再定义一个测试类Test,进行测试。 注意事项: 不要把局部变量提升为成员变量。
Demo:
public class Demo {
// 不要把局部变量提升为成员变量。
public int add(int a, int b) {
return a + b;
}
}
Test1:
public class Test1 {
public static void main(String[] args) {
Demo demo = new Demo();
int sum = demo.add(10, 20);
System.out.println("sum = " + sum); // 30
}
}
练习二:定义一个长方形类,定义求周长和面积的方法,然后定义一个测试类Test2,进行测试。 长方形: 属性:长, 宽, 面积, 周长 方法:求面积, 求周长
Rectangle:
public class Rectangle {
// 关键域
int length;
int width;
// 衍生域
int area; // 面积
int perimeter; // 周长
public Rectangle() {
}
public Rectangle(int length, int width) {
this.length = length;
this.width = width;
this.area = length * width;
this.perimeter = 2 * (length + width);
}
public int getArea() {
return area;
}
public int getPerimeter() {
return perimeter;
}
}
Test2:
public class Test2 {
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(20, 10);
int area = rectangle.getArea();
int perimeter = rectangle.getPerimeter();
System.out.println("area = " + area); // area = 200
System.out.println("area = " + rectangle.area); // area = 200
System.out.println("perimeter = " + perimeter); // perimeter = 60
System.out.println("perimeter = " + rectangle.perimeter); // perimeter = 60
}
}
练习三:定义一个类MyMath,提供基本的加减乘除功能,然后进行测试。 假设两个参数类型为int, int。
MyMath:
public class MyMath {
// 构造方法私有
private MyMath() {
}
public static int add(int a, int b) {
return a + b;
}
public static int minus(int a, int b) {
return a - b;
}
public static long multiply(int a, int b) {
return a * b;
}
public static double divide(int a, int b) {
return 1.0 * a / b;
}
}
Test3:
public class Test3 {
public static void main(String[] args) {
// Arrays arrays = new Arrays(); // 'Arrays()' has private access in 'java.util.Arrays'
// 这是一个工具类,没有属性,只有方法,应该将里面的方法都设为静态的,
// 这样可以用类名.方法名直接访问,不需要创建对象,所以该类的构造方法应该私有,这样在外部就不能创建对象。工具类Arrays构造方法也是这样设计的。
// 如果不提供自定义的private构造方法,系统将默认提供一个无参构造方法,用public修饰,外界可以访问。
int a = 3;
int b = 4;
System.out.println(MyMath.add(a, b)); // 7
System.out.println(MyMath.minus(a, b)); // -1
System.out.println(MyMath.multiply(a, b)); // 12
System.out.println(MyMath.divide(a, b)); // 0.75
}
}
10 static关键字
static:
静态的, 可以修饰成员(成员变量和成员方法)
特点:
随着类的加载而加载
优先于对象存在
被类的所有对象共享
这也是我们判断是否使用静态static关键字的条件
可以通过类名调用(推荐使用类名调用, 不要用对象名调用)
静态的成员是类所有,非静态成员是对象所有。
注意事项:
a.在静态方法中是没有 this 关键字的;
b.静态方法只能访问静态的成员;
c.非静态的方法可以访问静态的成员也可以访问非静态的成员。
成员变量和静态变量区别
a.所属不同
成员变量:对象
静态变量:类
b.内存中位置不同:
成员变量:堆
静态变量:方法区
c.生命周期不同:
成员变量:随着对象的创建而开始, 随着对象的死亡而消失
静态变量:随着类的加载而开始, 随着类的卸载而消失
d.调用方式不同:
成员变量:只能通过对象调用
静态变量:可以通过对象调用,也可以用类名调用(推荐使用类名调用)
Person:
public class Person {
static String nation; // 国籍,static修饰
String name;
int age;
public Person() {
}
public Person(String nation, String name, int age) {
this.nation = nation;
this.name = name;
this.age = age;
}
public void show() {
System.out.println("Person{nation=" + nation + ", name=" + name + ", age=" + age + "}");
}
public void m1() {
System.out.println("method1");
}
public static void m2() {
System.out.println("method2");
}
}
StaticDemo1:
public class StaticDemo1 {
int a;
static int b;
public void method1() {
}
public static void method2() {
}
public static void main(String[] args) {
Person p1 = new Person("中国", "迪丽热巴", 22);
Person p2 = new Person("中国", "古力娜扎", 23);
Person p3 = new Person("中国", "凤姐", 38);
p1.show(); // Person{nation=中国, name=迪丽热巴, age=22}
p2.show(); // Person{nation=中国, name=古力娜扎, age=23}
p3.show(); // Person{nation=中国, name=凤姐, age=38}
p3.nation = "America"; // nation是静态的,存放在方法区。
// Person.nation = "America"; // 作用与上面一行代码相同,也使得nation都变成了America。
p1.show(); // Person{nation=America, name=迪丽热巴, age=22}
p2.show(); // Person{nation=America, name=古力娜扎, age=23}
p3.show(); // Person{nation=America, name=凤姐, age=38}
// 从上面可以看出,nation全部变成了America。
p3.name = "罗玉凤"; // name是非静态的,存放在堆中。
// Person.name = "罗玉凤"; // 非静态变量只能通过对象访问,不能通过类名访问。
p1.show(); // Person{nation=America, name=迪丽热巴, age=22}
p2.show(); // Person{nation=America, name=古力娜扎, age=23}
p3.show(); // Person{nation=America, name=罗玉凤, age=38}
// 只有p3的name发生了修改,p1和p2的name均不会变化。
// 下面代码的结果一定要注意!!!
// 非静态成员从属于对象,访问前,对象一定不能为null,否则会出现空指针异常;
// 静态成员从属于类,推荐使用类名访问,如果使用对象名访问,会等同于使用类名访问,此时对象为null,也不会有空指针异常。
// 例如下面的System.out.println(p3.nation),代码在运行时,执行的还是System.out.println(Person.nation).
p3 = null;
// System.out.println(p3.name); // NullPointerException
System.out.println(p3.nation); // America
// p3.m1(); // NullPointerException
p3.m2(); // method2 // 执行的实际是Person.m2()
// System.out.println(this); // main方法是静态的,里面不能有this,否则报错。
// System.out.println(a); // 静态方法中不能有非静态的成员
System.out.println(b);
// method1(); // 静态方法中不能有非静态的成员
method2();
}
}
静态图解:
11 文档注释如果是public class 类名,则类名需要和.java文件名相同。
一个.java文件中最多只能有一个类被public修饰。
javadoc命令默认只解析public和protected的文档注释信息。
命令:javadoc -d 目录 -author -version 类名.java
例如:javadoc -d ./doc -author -version MyMath.java,即把生成的注释文档存放在当前目录下的doc文件夹中。
如何查看javadoc:
以Scanner为例:
包:java.util
如果不再java.lang包下,就需要导包
类的层次结构:public final class Scanner extends Object implements Iterator
继承关系
简单的概述:
一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
版本信息:
1.5(JDK的发展历史)
构造方法:
创建对象
方法:查看简要信息以及详细信息
String nextLine()
MyMath:
public class MyMath {
private MyMath() {
}
public static int add(int a, int b) {
return a + b;
}
public static int minus(int a, int b) {
return a - b;
}
public static long multiply(int a, int b) {
return a * b;
}
public static double divide(int a, int b) {
return 1.0 * a / b;
}
}
下面使用IDEA自动生成javadoc,步骤如下:
首先在IDEA中选中要生成javadoc的.java文件,在IDEA顶部工具栏找到Tools,下拉选择Generate JavaDoc,弹出如下对话框:
Other command line arguments写法:-encoding UTF-8 -charset UTF-8 -windowtitle "接口wiki" -link http://docs.Oracle.com/javase/8/docs/api,生成之后,打开index.html文件,就是所要的javadoc。
注意:"接口wiki"是index.html文件在浏览器中打开时页面的名字,可以自己指定。参考资料。
12 main方法public static void main(String[] args) {}
public: main方法是被JVM调用的, 所以需要能被JVM访问到, 所以访问权限得最大
static:main是程序的入口, 执行main之前没有对象。因此是静态的。
void: main方法是被JVM调用的,把值返回给JVM没有意义。
main: 只是一个约定俗称的名字
String[]:
用来接收键盘录入的数据的
java Main a bc d hello world
缺点:
a. 数据只会被保存成String类型
b. 不能和用户交互
因此在JDK1.5版本, 添加了Scanner(从1.5开始,之前都是通过args参数录入数据)这个工具
a. nextInt(), nextLine(), nextDouble()...
b. 可以和用户交互
Main:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
13 Math类
包:java.lang (不需要import,其它包下都需要用import导入) 继承结构:public final class Math extends Object 概述:Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。 版本:JDK1.0 构造方法:没有 方法:获取随机数 random(); static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0, 返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。
练习:
a. 获取随机数
b. 获取[1, 100]之间的随机整数
分析:
[0, 1.0) --> 乘100 --> [0, 100) --> + 1 --> [1, 101) --> 强转 --> int
c. 猜数字小游戏
随机生成一个[1, 100]的整数, 给别人猜
猜中了, 就结束
猜的数字大了, 就输出大了
猜的数字小了, 叫输出小了
MathDemo1:
import java.util.Scanner;
public class MathDemo1 {
public static void main(String[] args) {
// a.获取随机数
// b.获取[1, 100]之间的随机整数
int random = (int) (Math.random() * 100 + 1);
// System.out.println(random); // 63, [1, 100]之间的随机整数
// c.猜数字小游戏
while (true) {
System.out.println("请输入你要猜的数字(1~100):");
Scanner sc = new Scanner(System.in);
int guess = sc.nextInt();
if (guess > random) {
System.out.println("你猜的数字大了");
} else if (guess < random) {
System.out.println("你猜的数字小了");
} else {
System.out.println("恭喜猜对了");
break; // 跳出循环,结束游戏
}
}
}
}
14 代码块
代码块:
用{}括起来的代码
分类:
a.局部代码块
位置:方法里面(局部位置)
作用:限制局部变量的生命周期,及早释放,提高内存利用率。
b.构造代码块(语法糖,本质没有改变,但是方便程序员开发和理解)
位置:类中,方法外(成员位置)
作用:多个构造方法中相同的代码存放到一起,形成构造代码块,每次构造方法执行之前,都会先执行构造代码块。
c.静态代码块
位置:类中,方法外(成员位置)
作用:对类进行初始化,在类加载的时候执行,且只执行一次。
d.同步代码块(多线程的时候讲解)
a.局部代码块, CodeBlockDemo1:
public class CodeBlockDemo1 {
public static void main(String[] args) {
int a = 10;
// 局部代码块
{
int b = 20;
System.out.println("a = " + a); // 10
System.out.println("b = " + b); // 20
}
System.out.println("a = " + a); // 10
// System.out.println("b = " + b); // 变量b的生命周期在局部代码块中,这里b的生命周期已经结束,无法访问。
}
}
b.构造代码块, CodeBlockDemo2:
public class CodeBlockDemo2 {
// 构造代码块,是一种语法糖,使用XJad反编译生成的字节码文件中是没有构造代码块的,构造代码块中的代码会全部放在构造方法的最前面,即:
{
System.out.println("构造代码块");
}
public CodeBlockDemo2() {
System.out.println("无参构造方法");
}
public CodeBlockDemo2(int a) {
System.out.println("有参构造方法");
System.out.println("a = " + a);
}
public static void main(String[] args) {
CodeBlockDemo2 obj1 = new CodeBlockDemo2();
// 上面一行代码的运行结果:
CodeBlockDemo2 obj2 = new CodeBlockDemo2(10);
// 上面一行代码的运行结果:
}
}
c.静态代码块, CodeBlockDemo3:
public class CodeBlockDemo3 {
// 静态代码块
static {
System.out.println("静态代码块");
}
public CodeBlockDemo3() {
System.out.println("无参构造方法");
}
public CodeBlockDemo3(int a) {
System.out.println("有参构造方法");
System.out.println("a = " + a);
}
public static void main(String[] args) {
new CodeBlockDemo3();
//上面一行代码的执行结果:
new CodeBlockDemo3(10);
// 上面一行代码的执行结果:// 注意:静态代码块只执行一次
}
}
面试题及代码演示:
面试题:静态代码块,构造代码块,构造方法的执行顺序:
答案:静态代码块 --> 构造代码块 --> 构造方法
注意事项:
成员位置的代码不是按照编写的先后顺序去执行的,它有自己固定的执行顺序。
代码演示, Demo:
public class Demo {
{
System.out.println("构造代码块");
}
static {
System.out.println("静态代码块");
}
public static void main(String[] args) {
new Demo();
// 运行结果:
// 成员位置的代码不是按照编写的先后顺序去执行的,它有自己固定的执行顺序。
}
public Demo() {
System.out.println("构造方法");
}
}
15 作业
作业一:定义一个表示学生信息的类Student,要求如下:
(1)类Student的成员变量:
id表示学号;name表示姓名;gender表示性别;age表示年龄;java表示Java课程成绩。
(2)写一个比较标准的Student类
(3)根据类Student的定义,创建五个该类的对象,输出每个学生的信息,计算并输出这五个学生Java语言成绩的平均值,
以及计算并输出他们Java语言成绩的最大值和最小值 (可以考虑用数组做)。
Student:
public class Student {
private int id;
private String name;
private String gender;
private int age;
private int java;
public Student() {
}
public Student(int id, String name, String gender, int age, int java) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
this.java = java;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getJava() {
return java;
}
public void setJava(int java) {
this.java = java;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + ''' +
", gender='" + gender + ''' +
", age=" + age +
", java=" + java +
'}';
}
}
Proj3:
import java.util.Scanner;
public class Proj3 {
public static void main(String[] args) {
// 把5个学生的信息存放在数组中
Scanner sc = new Scanner(System.in);
Student[] students = new Student[5];
for (int i = 0; i < 5; i++) {
students[i] = new Student(); // 这时候必须要new一个Student,因为students数组默认初始化均为null
System.out.println("请输入第" + (i + 1) + "个学生的id:");
students[i].setId(Integer.parseInt(sc.nextLine()));
System.out.println("请输入第" + (i + 1) + "个学生的姓名:");
students[i].setName(sc.nextLine());
System.out.println("请输入第" + (i + 1) + "个学生的性别:");
students[i].setGender(sc.nextLine());
System.out.println("请输入第" + (i + 1) + "个学生的年龄:");
students[i].setAge(Integer.parseInt(sc.nextLine()));
System.out.println("请输入第" + (i + 1) + "个学生的java课程成绩:");
students[i].setJava(Integer.parseInt(sc.nextLine()));
}
// 输出每个学生的信息
for (int i = 0; i < 5; i++) {
System.out.println(students[i]);
}
// 这5个学生的Java课程的平均成绩
double avg = getJavaAvg(students);
System.out.println("avg = " + avg);
// 这5个学生的Java课程的最低成绩
int min = getJavaMin(students);
System.out.println("min = " + min);
// 这5个学生的Java课程的最高成绩
int max = getJavaMax(students);
System.out.println("max = " + max);
}
public static double getJavaAvg(Student[] students) {
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += students[i].getJava();
}
return 1.0 * sum / 5;
}
public static int getJavaMin(Student[] students) {
int min = students[0].getJava();
for (int i = 1; i < 5; i++) {
if (students[i].getJava() < min) {
min = students[i].getJava();
}
}
return min;
}
public static int getJavaMax(Student[] students) {
int max = students[0].getJava();
for (int i = 1; i < 5; i++) {
if (students[i].getJava() > max) {
max = students[i].getJava();
}
}
return max;
}
}
作业二:写一个数组的工具类ArrayTool, 要求提供遍历,求最大值,最小值,逆序,找元素在数组中最后出现的索引等操作。并生成帮助文档
ArrayTool:
public class ArrayTool {
public static void order(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
public static int max(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
public static int min(int[] arr) {
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
public static int[] reverse(int[] arr) {
int n = arr.length;
for (int i = 0; i < n / 2; i++) {
int temp = arr[i];
arr[i] = arr[n - i - 1];
arr[n - i - 1] = temp;
}
return arr;
}
public static int lastIndex(int[] arr, int target) {
int index = -1; // 如果没有出现,返回-1
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) index = i;
}
return index;
}
}
Proj2:
public class Proj2 {
public static void main(String[] args) {
int[] arr = {4, 5, 2, 3, 4, 1, 5};
ArrayTool.order(arr); // 4, 5, 2, 3, 4, 1, 5
System.out.println(ArrayTool.max(arr)); // 5
System.out.println(ArrayTool.min(arr)); // 1
int[] res = ArrayTool.reverse(arr);
ArrayTool.order(res); // 5, 1, 4, 3, 2, 5, 4
System.out.println(ArrayTool.lastIndex(arr, 4)); // 6,数组已经逆序了
}
}
生成的帮助文档见IDEA中的Day09模块。



