对象与类"/>
笔记:对象与类
笔记:对象与类
- 面向对象程序设计
- 预定义类
- Date类
- LocalDate类
- 更改器方法和访问器方法
- 模拟日历
- 用户自定义的类
- 例题:
- 详解
- 静态域与静态方法
- 方法参数
- 基本数据类型(数字或布尔值)
- 对象引用
- 对象构造
- 基本构造形式
- 特殊构造形式
面向对象程序设计
- 面向对象程序设计简称OPP,面向对象的程序是有对象组成,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。许多对象来自标准库,还有一些自定义的;
- 结构化程序设计通过设计一系列过程(算法)来解决问题,首先确定如何操作数据,然后决定如何组织数据;面向对象将数据放在第一位,然后考虑操作数据的算法;
- 对于规模较小的问题,结构化程序设计比较理想,但面向大规模的问题,如实现一个包含2000个过程的问题,将其分解为100个类,每个类中包含20左右的方法将更容易理解和查找错误;
- 类(class):构造对象的模板,由类构造对象的过程称为创建类的实例(instance);类将数据和行为组合在一个包里并对使用者隐藏了数据的实现方式,实现了封装;对象中的数据称为实例域,操纵数据的过程称作方法(method);
- 在类中最常见的关系是:
依赖(“use-a”):如果一个类的方法操纵另一个类的对象,就说一个类依赖另 一个类;
聚合(“has-a”):一个类的对象包含另一个类的对象;
继承(“is-a”):表示一般与特殊的关系,一个类不仅包含另一个类的方法,还拥有扩展的方法;
预定义类
对于已经定义好的类构造对象以及方法调用
Date类
import java.util.*;
public class Date01 {public static void main(String[] args) {// TODO 自动生成的方法存根//使用构造器构造新实例new Date()//构造器名字与类名相同并且要在构造器前使用new操作符 System.out.println(new Date());//返回当前日期与时间Date deadline=new Date();//对象变量并没有实际包含一个对象而是引用了一个对象System.out.println(deadline);//对象变量deadlineString s=deadline.toString();//调用类的方法}
}
LocalDate类
表示大家熟悉的日历表示法
java.util.Date和SimpleDateFormatter都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。
摘于:.html
import java.time.LocalDate;
public class LocalDate01 {public static void main(String[] args) {// TODO 自动生成的方法存根//不使用构造器构造实例//使用静态工厂方法代表调用构造器System.out .println(LocalDate.now());LocalDate newYearsEve=LocalDate.of(1999, 12, 31);int year=newYearsEve.getYear();int month=newYearsEve.getMonthValue();int day=newYearsEve.getDayOfMonth();System.out.println("新年是:"+year+"-"+month+"-"+day);LocalDate aThousandDaysLater=newYearsEve.plusDays(1000);//得到1000天后的日期System.out.println(aThousandDaysLater); }
}
更改器方法和访问器方法
import java.time.LocalDate;
public class LocalDate01 {public static void main(String[] args) {LocalDate newYearsEve=LocalDate.of(1999, 12, 31);LocalDate aThousandDaysLater=newYearsEve.plusDays(1000);//plusDays方法会生成一个新的对象,然后将对象赋值给aThousandDaysLater,对象状态不变System.out.println(aThousandDaysLater);//2002-09-26GregorianCalendar someDay=new GregorianCalendar(1999, 12, 31);someDay.add(Calendar.DAY_OF_MONTH, 1000);//更改器方法,someDay对象状态改变//只访问对象而不修改对象的方法称为访问器方法,如:getYear方法int year=someDay.get(Calendar.YEAR);int month=someDay.get(Calendar.MONTH);int day=someDay.get(Calendar.DAY_OF_MONTH);System.out.println("someDay是:"+year+"-"+month+"-"+day); }
}
模拟日历
import java.time.DayOfWeek;
public class CalendarTest {public static void main(String[] args) {// TODO 自动生成的方法存根LocalDate date=LocalDate.now();int month=date.getMonthValue();int today=date.getDayOfMonth();date=date.minusDays(today-1);//将date设为这个月第一天DayOfWeek weekday=date.getDayOfWeek();//得到这一天为星期几int value=weekday.getValue();System.out.println("Mon Tue Wed Thu Fri Sat Sun");for(int i=1;i<value;i++) {System.out.print(" ");}while(date.getMonthValue()==month) {System.out.printf("%3d",date.getDayOfMonth());if(date.getDayOfMonth()==today) {System.out.print("*");//日期为当天用*表示}else System.out.print(" ");date=date.plusDays(1);if(date.getDayOfWeek().getValue()==1) System.out.println();//为星期一就换行}if(date.getDayOfWeek().getValue()!=1) System.out.println();}
}
用户自定义的类
例题:
import java.time.LocalDate;
public class EmployeeTest {public static void main(String[] args) {Employee[] staff=new Employee[3];staff[0]=new Employee("Cral", 5600, 1999, 2, 20);staff[1]=new Employee("Kral", 6600, 1998, 3, 15);staff[2]=new Employee("Dral", 7600, 1997, 4, 10);for(Employee e:staff) {e.raiseSalary(10);}for(Employee e:staff) {System.out.println("职工 "+e.getName()+" 在 "+e.getHireDay()+" 入职,当前工资为 "+e.getSalary());}}
}class Employee{//实例域 fieldprivate String name;private double salary;private LocalDate hireDay;//构造器 constructorpublic Employee(String n,double s,int year,int month,int day) {name=n;salary=s;hireDay=LocalDate.of(year, month, day);}//四个方法 methodpublic String getName() {return name;}public double getSalary() {return salary;}public LocalDate getHireDay() {return hireDay;}public void raiseSalary(double byPercent) {double raise=salary*byPercent/100;salary=salary+raise;}
}
详解
- 构造器与类同名,每个类可以有一个以上的构造器,构造器没有返回值,总伴随new操作符一起调用;
- 关键词private保证只有类自身的方法可以访问实例域,而其他类不能读写这些实例域,一般不提倡使用public修饰实例域;
- 对于 e.raiseSalary(10); 其中 e 称为隐式(implicit)参数,是出现在方法名前的Employee类对象;括号里面的10 称为显示(explicit)参数,是位于方法名后括号里面的值,同理double byPercent也是显示参数;关键字this为隐式参数,例如:
public void raiseSalary(double byPercent) {double raise=this.salary*byPercent/100;this.salary=this.salary+raise;}
}
4.私有方法:尽管大多数方法为公有的但是也可以将它设计为私有的;
5.final实例域:可以将实例域定义为final,必须确保在一个构造器中被赋值,并且在后面的操作中无法更改,final修饰符大都用于基本类型域或不可变类的域(例如String为不可变类而String Builder不是不可变类);
静态域与静态方法
- 静态域:静态域也称为类域,每个类中只有一个定义为static的域,每一个对象有实例域的拷贝,静态域相当于是同一类的众多对象的唯一标识符,静态域属于类而不单独属于某一个对象;
- 静态常量,例如:
public class Math{
. . .
public static final double PI=3.14159265358979323846;
. . .
}
中可以通过Math.PI来使用这个常量,而实例域只能通过类的对象来访问; - 静态方法:静态方法不能向对象实施操作,即没有隐式参数;静态方法是没有this参数的方法,不能使用实例域,但是可以访问自身的静态域;可以通过类名调用这个方法;在一个方法不需要访问对象状态或只需要访问静态域的时候可以选择使用静态域;
- 工厂方法(factory method):例如LocalDate.of、LocalDate.now
使用工厂方法原因:
1.不希望构造器名字和类名一样 ;
2.使用构造器时无法改变所构造的对象类型; - main方法是一种静态方法;
- 练习:
import java.time.LocalDate;
public class Statictest { public static void main(String[] args) {Employee02[] staff=new Employee02[3];staff[0]=new Employee02("Cral", 5600);staff[1]=new Employee02("Kral", 6600);staff[2]=new Employee02("Dral", 7600);for(Employee02 e:staff) {e.setId();System.out.println("name="+e.getName()+",id="+e.getId()+",salary="+e.getSalary());}//静态方法int n=Employee02.getNextId();System.out.println("Next available id="+n);}
}
class Employee02{ //静态域private static int nextId=1;private String name;private double salary;private int id;public Employee02(String n,double s) {name=n;salary=s;id=0;}public String getName() {return name;}public double getSalary() {return salary;}public int getId() {return id;}public void setId() {id=nextId;nextId++;}public static int getNextId() {return nextId;}//每一个类可以有一个类方法,以下的main方法用于对类进行测试public static void main(String[] args) {Employee02 e=new Employee02("Harry",50000);System.out.println("name="+e.getName()+",id="+e.getId()+",salary="+e.getSalary());}
}
方法参数
- Java程序设计语言总是采用按值调用,方法得到的是参数变量的拷贝,无法修改参数变量的内容;
- 方法参数有两种类型:
基本数据类型(数字或布尔值)
public static void tripleValue(double x){x=x*3;
}
double percent=10;
tripleValue(percent);
//先执行x=percent进行拷贝,x->30而percent->10;
对象引用
public static void tripleValue(Employee x){x.raiseSalsry(200);
}
Employee e=new Employee(...);
tripleValue(e);
//x首先初始化为e的拷贝,然后两者同时引用raiseSalary方法,所以e的薪资同时改变;
然而并不能因此认为Java是按引用调用,反例:
public static void swap(Employee x,Employee y){Employee temp=x;x=y;y=temp;
}
......
Employee a=new Employee(...);
Employee b=new Employee(...);
swap(a,b);
//无法实现a,b交换,因为交换成功的是x,y这两个引用,最后x,y被舍弃,a,b依旧调用以前所引用的对象
总结:
- 一个方法无法改变基本数据类型参数;
- 一个方法可以改变对象参数的状态;
- 一个方法无法让对象参数引用另一个新的对象。
对象构造
基本构造形式
- 有些类可以有多个构造器(重载overloading);
- 如果编写一个类的时候没有编写构造器,系统会提供一个无参数的构造器,构造器将所有实例域设置为默认值,但是如果编写的时候提供了至少一个构造器,但是没有提供无参构造器,则在构造对象的时候没有提供参数将视为不合法;
特殊构造形式
- 调用另一个构造器:如果构造器的第一个语句形如this(…),表示将调用同一个类中的另一个构造器,例如:
public Employee(double s){//Employee(String s,double s);this("Employee #"+nextId,s);nextId++;
}
- 初始化块:在一个类的声明中,可以包含多个代码块,只要构造对象,就会执行这些块;
- 测试:
import java.time.LocalDate;
import java.util.*;
public class ConstructorTest {public static void main(String[] args) {Employee03[] staff=new Employee03[3];staff[0]=new Employee03("Cral", 5600);staff[1]=new Employee03(6600);staff[2]=new Employee03();for(Employee03 e:staff) {System.out.println("name= "+e.getName()+",id="+e.getId()+" salary= "+e.getSalary());}}
}
class Employee03{private static int nextId;private int id;private double salary;private String name="";//静态初始化块static {Random generator=new Random();nextId=generator.nextInt(10000);//生成0~9999之间的随机数}//对象初始化块{id=nextId;nextId++;}//构造器重载public Employee03(String n,double s){name=n;salary=s;}public Employee03(double s){//Employee03(String s,double s);this("Employee #"+nextId,s);nextId++;}public Employee03(){//无参构造器}public int getId() {return id;}public String getName() {return name;}public double getSalary() {return salary;}
}
--------全文参考《Java核心技术卷1》
更多推荐
笔记:对象与类
发布评论