一、复习
1.1 方法的参数传递机制
1、基本数据类型:实参给形参传的是数据值的副本,形参接下来的修改与实参无关。
2、引用数据类型:实参给形参传的是地址值的副本,形参接下来对数组元素的修改与实参有关。当形参变量指向一个新的数组对象时,接下来的修改就与实参无关了。
1.2 方法调用的过程
- 入栈:方法被调用时,就会在栈内存开辟一块空间,用于存储这个方法的局部变量、操作数栈等信息
- 出栈:方法调用结束(要么方法体语句全部执行完,遇到 return 语句,遇到异常),就会释放这个方法占用的栈内存空间。
- 栈内存的结构特点:先进后出(FILO,first in last out)或后进先出(LIFO,last in first out)
1.3 方法的重载(overload)
在同一个类中,方法名相同,形参列表不同(形参的类型、个数、顺序不同,与形参名无关)的两个或多个方法称为重载。重载与返回值类型、修饰符也无关。
1.4 可变参数
【修饰符】 class 类名{
【修饰符】 返回值类型 方法名(【数据类型 普通参数名, 数据类型 普通参数名,】 数据类型... 可变参数名){
//...
}
}
一个方法最多只有 1 个可变参数,而是是最后一个参数。
可变参数部分在调用时,可以传入对应的数组 或 传入 0~n 个元素
1.5 递归
一个方法出现了自己调用自己的形式就是递归。递归调用必须有条件,或必须有出口,否则会出现 StackOverflowError 栈内存溢出错误。
1.6 类与对象
类:一类具有相同特征的事物的抽象描述。
对象:是这类事物中一个具体的个体、实体、实例。
【修饰符】 class 类名{
}
类名 对象名 = new 类名();
1.7 包
包的作用:管理不同的.java 文件,可以避免类的重名。
包名的命名习惯:
- 全部小写
- 单词之间使用.分割
- 一般用公司域名倒置的形式:例如:com.atguigu.xxx
1.8 成员变量
【修饰符】 class 类名{
【修饰符】 数据类型 成员变量名称;
}
静态变量 | 实例变量 | |
---|---|---|
是否有 static | 有 static | 没有 static |
是否被多个对象对象 | 共享 | 每一个对象独立的 |
是否依赖对象 | 否 | 是 |
在类的外部使用时 | 类名.静态变量(推荐) 对象名.静态变量(不推荐) | 对象名.实例变量 |
二、类的成员
2.1 类的成员之一:成员变量(续)
成员变量:field 字段
2.1.1 成员变量是引用数据类型
案例演示
除了 8 种基本数据类型,以及 String 类型,其他的像数组、自己定义的类都可以当做数据类型。
package com.atguigu.field;
public class Husband {//丈夫
public String name;
public Wife wife;
}
package com.atguigu.field;
public class Wife {//妻子
public String name;
public Husband husband;
}
package com.atguigu.field;
public class TestHusbandWife {
public static void main(String[] args) {
//创建一个Husband类的对象
Husband h = new Husband();
h.name = "李刚";
//创建一个Wife类的对象
Wife w = new Wife();
w.name = "翠花";
/*
一个对象名后面能.出什么,要看它是什么类型的对象。
h是Husband类型的,它就可以.出Husband的成员,即h.name和h.wife都OK。
此时h.wife是Wife类型的,它就可以.出Wife类的成员,即可以 h.wife.name 或 h.wife.husband
*/
//System.out.println("男:" + h.name +",他的妻子的名字:" + h.wife.name);
//上面这句代码编译没问题,但是运行时会报错,h.wife是null,会发生空指针异常
// h.wife = 一个Wife类型的对象;
h.wife = w;
System.out.println("男:" + h.name +",他的妻子的名字:" + h.wife.name);
w.husband = h;
System.out.println("女:" + w.name +",她的丈夫的名字:" + w.husband.name);
}
}
练习题
package com.atguigu.exer5;
//(1)声明一个MyDate类型,有属性:年year(int类型),月month(int类型),日day(int类型)
public class MyDate {//日期
public int year;//年
public int month;//月
public int day;//日
}
package com.atguigu.exer5;
public class TestMyDate {
public static void main(String[] args) {
//(2)在测试类TestMyDate类中,创建两个日期对象,一个日期赋值为今年六一儿童节日期,
// 一个日期赋值为今年程序员节日期,并显示
MyDate childrenDay = new MyDate();
childrenDay.year = 2025;
childrenDay.month = 6;
childrenDay.day = 1;
System.out.println("今年六一儿童节:" + childrenDay.year +"年" + childrenDay.month+"月" + childrenDay.day+"日");
MyDate programDay = new MyDate();
programDay.year =2025;
programDay.month =10;
programDay.day =24;
System.out.println("今年程序员节:" + programDay.year +"年" + programDay.month+"月" + programDay.day+"日");
}
}
package com.atguigu.exer5;
//(3)声明另一个Employee类型,有属性:姓名name(String类型),生日birthday(MyDate类型)
public class Employee {//员工
public String name;
public MyDate birthday;
//只要是8种以外的数据类型,都是引用数据类型,
// 默认值是null,null代表没有对象给它赋值
}
package com.atguigu.exer5;
public class TestEmployee {
public static void main(String[] args) {
// (4)在测试类TestEmployee中的main中,创建两个员工对象,并为他们的姓名和生日赋值,并显示员工的姓名和生日
Employee e1 = new Employee();
e1.name ="张三";
e1.birthday = new MyDate();
//这种写法,是把变量的声明与给变量的赋值操作分开了
//声明在Employee类中 MyDate birthday;
//这里只是赋值。至于赋值什么东西?要看它什么类型,是MyDate类,就给它一个MyDate类型的对象
e1.birthday.year = 1996;
e1.birthday.month = 5;
e1.birthday.day = 1;
System.out.println("e1的信息:" + e1.name +",生日:" +e1.birthday.year +"年" + e1.birthday.month+"月" + e1.birthday.day+"日");
Employee e2 = new Employee();
e2.name ="李四";
MyDate my = new MyDate();
my.year = 2000;
my.month = 6;
my.day = 1;
e2.birthday = my;
System.out.println("e2的信息:" + e2.name +",生日:" +e2.birthday.year +"年" + e2.birthday.month+"月" + e2.birthday.day+"日");
}
}
2.1.2 成员变量内存分析
1、JVM 内存结构
JVM 架构图如下:
JVM 运行时数据区:
JDK7 和 8 版本每一块内存区域说明:
内存区域 | JDK7 | JDK8 |
---|---|---|
方法区 | - 实现为永久代 - 类信息(类元数据) - 运行时常量池 - JIT 编译后的代码 - 静态变量 | -实现为元空间,位于本地内存(Native Memory) - 类信息(类元数据) - 运行时常量池 - JIT 编译后的代码 |
堆 | - 对象实例(包括数组) - 字符串常量池(JDK7 从永久代移至堆) | - 对象实例(包括数组) - 字符串常量池 - 静态变量(JDK8 从永久代移至堆) |
Java 虚拟机栈 | - 栈帧:局部变量表、操作数栈、动态链接、方法出口 | 与 JDK7 相同 |
本地方法栈 | - Native 方法调用的栈帧 | 与 JDK7 相同 |
程序计数器 | 当前线程执行的字节码指令地址 | 与 JDK7 相同 |
2、实例变量的内存分析
3、静态变量与实例变量的内存分析
4、引用数据类型成员变量的内存分析
说明:凡是引用数据类型的成员变量,它们的默认值是 null,如果没有给它赋值对象,通过它们.xx 的时候就会发生空指针异常,因为它们没有指向任何内存,找不到对应的数据。
2.2 类的成员之二:构造器
构造器:constructor
2.2.1 构造器的作用
构造器的作用是为对象的实例变量初始化或赋值的,在new对象
的同时给它们赋值。
2.2.2 构造器如何声明和使用
- 每一个类都有构造器
- 如果一个类,程序员没有给它写构造器,那么编译器就会给它自动添加一个默认的无参构造。
- 程序员也可以手动编写构造器,你可以编写无参构造,也可以编写有参构造。但是要注意,一旦你手动编写了构造器(无论你写的是无参还是有参的),编译器就不会给你自动添加默认的无参构造。
- 构造器与方法很像,但是不一样。
- 构造器没有返回值类型,也不能写返回值类型
- 构造器的修饰符只能是 public、protected、缺省(不写)、private 四选 1 ,不能加 static、final 等其他单词
- 构造器的名字必须与类名完全一致,包括大小写
声明语法格式:
【修饰符】 class 类名{
【public或protected或缺省或private】 类名(){//无参构造
}
【public或protected或缺省或private】 类名(形参列表){//有参构造
实例变量 = 形参名;
}
}
2.2.3 构造器可以用快捷键生成
package com.atguigu.constructor;
public class Book {
public String name;
public double price;
//快捷键 Alt + Insert,部分同学的键盘模式,需要同时按Fn
public Book() {//无参构造
}
public Book(String name, double price) {//全参构造
this.name = name;
this.price = price;
}
public Book(String name) {//部分参数构造器
this.name = name;
}
//按照上面的代码,程序员有就有3种方式来创建Book对象
}
2.4.4 this 关键字
this 代表当前对象,在构造器中表示你正在 new 的哪个对象。
用法:
- ths.实例变量:当实例变量与形参等局部变量重名时,需要在实例变量前面加 this.以区分。
this()
或this(参数)
:调用本类的其他构造器。它们必须在构造器的首行。- this.方法() :等单独讲成员方法的时候再说,这种用法几乎可以忽略不计,因为这种情况,this.都是省略。
2.4.5 示例代码
示例 1:有默认无参构造
package com.atguigu.constructor;
public class Student {
public String name;
public int score;
}
package com.atguigu.constructor;
public class TestStudent {
public static void main(String[] args) {
Student s = new Student(); //默认的无参构造
System.out.println(s.name+"," + s.score);
}
}
示例 2:没有默认无参构造
package com.atguigu.constructor;
public class Teacher {
public String name;
public double salary;
public Teacher(String n, double s) {
name = n;
salary = s;
}
}
package com.atguigu.constructor;
public class TestTeacher {
public static void main(String[] args) {
// Teacher t1 = new Teacher();//报错,没有默认的无参构造
Teacher t2 = new Teacher("柴林燕", 15000);
}
}
示例 3:手动定义无参和有参构造
package com.atguigu.constructor;
public class Employee {
public String name;
public int age;
public char gender;
public Employee(){//无参构造
}
public Employee(String n, int a, char g){//有参构造
name = n;
age = a;
gender = g;
}
}
package com.atguigu.constructor;
public class TestEmployee {
public static void main(String[] args) {
//用无参构造创建Employee对象
Employee e1 = new Employee();
System.out.println("e1姓名:" + e1.name +",年龄:" + e1.age +",性别:" + e1.gender);
//用有参构造创建Employee对象
Employee e2 = new Employee("李刚", 25, '男');
System.out.println("e2姓名:" + e2.name +",年龄:" + e2.age +",性别:" + e2.gender);
}
}
示例 4:构造器不能加返回值类型
package com.atguigu.constructor;
public class Circle {
public double radius;
public void Circle(){//不是构造器
System.out.println("我是构造器????");
}
}
package com.atguigu.constructor;
public class TestCircle {
public static void main(String[] args) {
Circle c = new Circle();//用的是默认的无参构造
c.Circle();//调用普通方法
}
}
示例 5:快捷键生成构造器
package com.atguigu.constructor;
public class Book {
public String name;
public double price;
//快捷键 Alt + Insert,部分同学的键盘模式,需要同时按Fn
public Book() {//无参构造
}
public Book(String name, double price) {//全参构造
this.name = name;
this.price = price;
}
public Book(String name) {//部分参数构造器
this.name = name;
}
//按照上面的代码,程序员有就有3种方式来创建Book对象
}
示例 6:this 调用本类构造器
package com.atguigu.constructor;
public class Goods {
public int id;
public String name;
public double price;
public int stock;
public String date;
public Goods() {
System.out.println("一个商品对象被创建了");
}
public Goods(int id, String name, double price) {
this();//调用本类无参构造
this.id = id;
this.name = name;
this.price = price;
}
public Goods(int id, String name, double price, int stock, String date) {
// this.id = id;
// this.name = name;
// this.price = price;
this(id,name,price);//调用本类另一个有参构造,为id,name,price属性赋值
this.stock = stock;
this.date = date;
}
}
2.3 面向对象基本特征之一:封装
面向对象的基本特征:封装、继承、多态
2.3.1 为什么有封装?
生活中快递包裹的意义:
- 保护隐私
- 为了安全
- 便于运输
Java 中类的封装的意义:
- 保护隐私:有时候会故意隐藏类的内部实现细节,不需要使用者了解过多。例如:String 代表一串字符,早期用的是 char[]存储一组字符,现在用 byte[]存储一组字符
- 便于维护和使用:例如 String,内部的实现细节变化了,不影响外部的使用
封装的层面可大可小:
- 大:达到项目的层面,例如:咱们的项目调用 AI 大模型项目,咱们项目调用支付宝的支付功能,无需了解也无从得知它们的内部实现细节。
- 小:属性的私有化
2.3.2 权限修饰符
Java 给我们提供了 4 种权限修饰符的情况,共有 3 个单词:
private | 缺省(不写) | protected | public | |
---|---|---|---|---|
本类 | √ | √ | √ | √ |
本包 | × | √ | √ | √ |
跨包的子类 | × | × | √ | √ |
跨包的非子类 | × | × | × | √ |
1、类(不含内部类)也有权限修饰符:只有 2 种,public 或缺省。
- public 的类,可以跨包使用
- 缺省的非公共的类,不可以跨包使用。
2、类的成员也可以有权限修饰符:四种都可以
类的成员有:成员变量、构造器、成员方法、成员内部类、代码块。这里先以成员变量为例演示。
案例 1
package com.atguigu.encapsolation.one;
public class Student {//公共的
}
/*class Student {//缺省的
}*/
/*
protected class Student {//错误,不可以在class前面写private和protected
}*/
package com.atguigu.encapsolation.two;
import com.atguigu.encapsolation.one.Student;
public class TestStudent {
public static void main(String[] args) {
Student s = new Student();
}
}
案例 2
package com.atguigu.encapsolation.one;
public class Father {//父亲
private int a;
int b;
protected int c;
public int d;
public void show(){//成员方法,本类的方法,可以访问本类的所有成员变量(不讨论静态非静态问题),只看权限修饰符问题
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
}
}
package com.atguigu.encapsolation.one;
public class SamePackageTest {
public static void main(String[] args) {
Father f = new Father();
// System.out.println("f.a = " + f.a);//因为a是private,出了Father就不可以直接访问
System.out.println("f.b = " + f.b);
System.out.println("f.c = " + f.c);
System.out.println("f.d = " + f.d);
}
}
跨包:
package com.atguigu.encapsolation.two;
import com.atguigu.encapsolation.one.Father;
//Son类继承Father,即Son类是Father类的子类
public class Son extends Father {//儿子
public void print(){
// System.out.println("a = " + a);
// System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
//跨包的子类中,只能访问父类中public和protected的成员,不可以访问父类中private和缺省的
}
}
package com.atguigu.encapsolation.two;
import com.atguigu.encapsolation.one.Father;
public class DifferentPackageTest {
public static void main(String[] args) {
Father f = new Father();
// System.out.println("f.a = " + f.a);//错误
// System.out.println("f.b = " + f.b);//错误
// System.out.println("f.c = " + f.c);//错误
System.out.println("f.d = " + f.d);
//跨包非子类,只有public可见,其他都不可见
}
}
2.3.3 属性私有化
属性私有化是指给类的成员变量加 private 修饰。
第一步:给成员变量加 private
第二步:给这些成员变量加 get/set 方法
- get/set 方法的命名规则,不能随意,习惯上都是 get/set +属性名,且属性名的首字母改为大写
- 其中 boolean 类型属性,get 方法一般把 get 单词换成 is
- 当成员变量是静态的,那么它们的 get/set 也是静态的。
- 在静态的 set 方法中,形参与静态变量重名时,通过“类名.静态变量”进行区分
- 当成员变量是非静态的,它们的 get/set 也是非静态的
- 在非静态的 set 方法中,形参与实例变量重名时,通过“this.实例变量”进行区分
package com.atguigu.encapsolation.one;
public class Rectangle {
/* public double length;
public double width;*/
private double length;
private double width;
public Rectangle() {
}
public Rectangle(double length, double width) {
if(length<=0 || width<=0){
System.out.println("长、宽必须是正数");
return;
}
this.length = length;
this.width = width;
}
//set:设置或修改某个属性的值
public void setLength(double length){
if(length<=0){
System.out.println("长必须是正数");
return;
}
this.length = length;
}
public void setWidth(double width){
if(width<=0){
System.out.println("宽必须是正数");
return;
}
this.width = width;
}
//get是用于获取某个属性的值
public double getLength(){
return length;
}
public double getWidth(){
return width;
}
}
package com.atguigu.encapsolation.one;
public class TestRectangle {
public static void main(String[] args) {
/* Rectangle r1 = new Rectangle();
r1.length = 6;
r1.width = 4;
System.out.println("r1的长和宽:" + r1.length +"," +r1.width);
Rectangle r2 = new Rectangle(9,5);
System.out.println("r2的长和宽:" + r2.length +"," +r2.width);
Rectangle r3 = new Rectangle();
r3.length = -8;
r3.width = -6;
System.out.println("r3的长和宽:" + r3.length +"," +r3.width);
Rectangle r4 = new Rectangle(-9,-3);
System.out.println("r4的长和宽:" + r4.length +"," +r4.width);*/
//上面的代码必须对应length和width是public的情况
Rectangle r1 = new Rectangle();
r1.setLength(6);
r1.setWidth(4);
System.out.println("r1的长和宽:" + r1.getLength() +"," +r1.getWidth());
Rectangle r2 = new Rectangle(9,5);
System.out.println("r2的长和宽:" + r2.getLength() +"," +r2.getWidth());
r2.setWidth(6);
System.out.println("r2的长和宽:" + r2.getLength() +"," +r2.getWidth());
}
}
2.3.4 可以用快捷键生成 get/set
package com.atguigu.encapsolation.one;
public class Employee {
//属性私有化
private static String company;//公司名
private String name;
private double salary;
private boolean marry;
//快捷键Alt+ Insert,部分同学可能需要同时按Fn
public static String getCompany() {
return company;
}
public static void setCompany(String company) {
Employee.company = company;
// this.company = company;//错误
}
public boolean isMarry() {
return marry;
}
public void setMarry(boolean marry) {
this.marry = marry;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.atguigu.encapsolation.one;
public class TestEmployee {
public static void main(String[] args) {
Employee e1 = new Employee();
e1.setName("张三");
e1.setSalary(15000);
e1.setMarry(true);
System.out.println("e1的姓名:" + e1.getName() +",薪资:" + e1.getSalary() +",婚否:" + e1.isMarry());
Employee e2 = new Employee();
e2.setName("李四");
e2.setSalary(12000);
e2.setMarry(false);
System.out.println("e2的姓名:" + e2.getName() +",薪资:" + e2.getSalary() +",婚否:" + e2.isMarry());
}
}
2.4 类的成员之三:成员方法
2.4.1 静态方法和非静态方法
方法:method,在别的语言中,习惯叫做 function 函数。
在 Java 中方法是不能独立存在的,必须写在类中,即方法是类的成员。
成员方法可以分为 2 类:
- 静态方法,又称为类方法
- 非静态方法,又称为实例方法
静态方法 | 非静态方法/实例方法 | |
---|---|---|
方法的前面有没有 static | 有 static | 没有 static |
方法里面是否可以直接访问本类的其他成员 | 只能访问本类的静态成员 | 可以访问本类的所有成员 |
是否可以出现 this | 不可以出现 this | 可以出现 this |
是否依赖当前类的对象 | 不依赖 | 依赖 |
跨类调用时 | 类名.静态方法(推荐) 对象名.静态方法(不推荐,IDEA 不主动提示) | 对象名.非静态方法 |
该如何选择呢?什么时候用静态方法,什么时候用非静态方法呢?
如果在这个方法中,需要访问本类的 非静态成员(实例变量等),那么这个方法必须是非静态的方法。
如果在这个方法中,只访问本类的 静态成员,理论上这个方法可以是静态的,也可以是非静态的,但是建议是静态的。
package com.atguigu.method;
public class Chinese {//中国人
//country是国家名,每一个中国人应该共享同一个国家名,所以必须是static
private static String country;//国家名 静态变量或称为类变量
//name和age是每一个人独立的,所以它们不能是static
private String name;//姓名 实例变量
private int age;//年龄 实例变量
//构造器 快捷键 Alt + Insert
public Chinese() {//无参构造
}
public Chinese(String name, int age) {//有参构造
this.name = name;
this.age = age;
}
//get/set方法 快捷键 Alt + Insert
public static String getCountry() {
return country;
}
public static void setCountry(String country) {
Chinese.country = country;
}
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 static void show(){//静态方法,或类方法
System.out.println("国家名:" + country);
// System.out.println("姓名:" + name);//报错
// System.out.println("年龄:" + age);//报错
}
public void display(){//非静态方法,或实例方法
System.out.println("国家名:" + country);
System.out.println("姓名:" + name);
System.out.println("年龄:" + age);
}
}
2.4.2 方法的内存分析
所有方法都有调用者:
- 静态方法:它的调用者时这个类本身
- 非静态方法:它的调用者是某个对象,在当前非静态方法中,由 this 来代表调用这个方法的当前对象。同时 this 可以取得这个对象的所有的属性值。
2.4.3 案例
1、案例 1
package com.atguigu.exer5_2;
//(1)声明一个MyDate类型,有属性:年year(int类型),月month(int类型),日day(int类型)
public class MyDate {//日期
private int year;//年
private int month;//月
private int day;//日
//构造器,快捷键Alt + Insert
public MyDate() {
}
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
//get/set
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public String getInfo(){
return year +"年" + month +"月" + day + "日";
}
}
package com.atguigu.exer5_2;
public class TestMyDate {
public static void main(String[] args) {
//(2)在测试类TestMyDate类中,创建两个日期对象,一个日期赋值为今年六一儿童节日期,
// 一个日期赋值为今年程序员节日期,并显示
MyDate childrenDay = new MyDate();
childrenDay.setYear(2025);
childrenDay.setMonth(6);
childrenDay.setDay(1);
// System.out.println("今年六一儿童节:" + childrenDay.getYear() +"年" + childrenDay.getMonth()+"月" + childrenDay.getDay()+"日");
System.out.println("今年六一儿童节:" + childrenDay.getInfo());
MyDate programDay = new MyDate();
programDay.setYear(2025);
programDay.setMonth(10);
programDay.setDay(24);
// System.out.println("今年程序员节:" + programDay.getYear() +"年" + programDay.getMonth()+"月" + programDay.getDay()+"日");
System.out.println("今年程序员节:" + programDay.getInfo());
}
}
package com.atguigu.exer5_2;
//(3)声明另一个Employee类型,有属性:姓名name(String类型),生日birthday(MyDate类型)
public class Employee {//员工
private String name;
private MyDate birthday;
//构造器,快捷键Alt + Insert
public Employee() {
}
public Employee(String name, MyDate birthday) {
this.name = name;
this.birthday = birthday;
}
//手写,单独定制
public Employee(String name, int year, int month, int day){
this.name = name;
birthday = new MyDate(year, month, day);//=右边用的是MyDate类的构造器,意味着MyDate类须有一个全参构造
}
//get/set,快捷键Alt + Insert
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
public String getInfo(){
return "姓名:" + name +",生日:" + birthday.getInfo();
}
}
package com.atguigu.exer5_2;
public class TestEmployee {
public static void main(String[] args) {
// (4)在测试类TestEmployee中的main中,创建两个员工对象,并为他们的姓名和生日赋值,并显示员工的姓名和生日
Employee e1 = new Employee();
e1.setName("张三");
/* MyDate date = new MyDate(1996,12,1);
e1.setBirthday(date);*/
//下面这句代码涉及到一个名词:匿名对象
e1.setBirthday(new MyDate(1996,12,1));
System.out.println("e1的信息:" + e1.getInfo());
Employee e2 = new Employee();
e2.setName("李四");
MyDate my = new MyDate();
my.setYear(2000);
my.setMonth(6);
my.setDay(1);
e2.setBirthday(my);
System.out.println("e2的信息:" + e2.getInfo());
Employee e3 =new Employee("王五",2001,2,3);
System.out.println("e3的信息:" + e3.getInfo());
}
}
2、案例 2
package com.atguigu.exer2_2;
public class Triangle {
private double a;
private double b;
private double c;
public Triangle() {
}
public Triangle(double a, double b, double c) {
//(1)边长不能为负数或0
//(2)三角形要求任意两边之和大于第三边
if(a<=0 || b<=0 || c<=0 || a+b<=c || b+c<=a ||a+c<=b){
System.out.println(a+"," + b +"," + c +"的值无法构成三角形");
}else {
this.a = a;
this.b = b;
this.c = c;
}
}
//get/set
public double getA() {
return a;
}
public void setA(double a) {
this.a = a;
}
public double getB() {
return b;
}
public void setB(double b) {
this.b = b;
}
public double getC() {
return c;
}
public void setC(double c) {
this.c = c;
}
//其他方法
public double area(){
double p = (a+b+c)/2;
return Math.sqrt(p * (p-a) * (p-b) * (p-c));
}
public double perimeter(){
return a+b+c;
}
public String getInfo(){
return "三边长:" + a + "," + b +"," + c +
",面积:" + area() +
",周长:" + perimeter();
}
}
package com.atguigu.exer2_2;
public class TestTriangle {
public static void main(String[] args) {
Triangle t1 = new Triangle();
t1.setA(6);
t1.setB(6);
t1.setC(6);
System.out.println(t1.getInfo());
Triangle t2 = new Triangle(3,4,5);
System.out.println(t2.getInfo());
Triangle t3 = new Triangle(1,1,5);
System.out.println(t3.getInfo());
}
}
2.4.4 标准的 Javabean
bean:豆
java:爪哇岛,印尼产咖啡豆的地方
java 的类,通常被比喻为咖啡豆
标准的 Javabean 有一些约定成俗的潜规则:
- 所有的属性都是 private
- 为他们提供公共的 get/set 方法
- 保留无参构造
- 至于有参构造,可选
- 建议重写 hashCode、equals、toString 等(下周再讲)
- 这个类是具体的,而不是抽象的(关于抽象类也是下周讲)