一、概述
(一)类
类是构造对象的模板
由类构造对象的过程称为:创建类的实例(对象)
封装:将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。关键:本类方法不能直接访问他类实例域。
类之间的关系:
依赖 uses-a:A类操作B类对象,耦合度高
聚合 has-a:A类对象包含B类对象
继承 is-a:A类是B类的扩展
(二)对象
实例域:对象中的数据
对象的状态:每个特定的对象都有一组特定的实例域值
方法:操作数据的过程
对象的三个特征:
对象的行为:用可调用的方法定义(方法)
对象的状态:描述当前特征的信息。状态的改变必须通过调用方法实现(域)
对象的标识:每个对象唯一的身份(地址,hashcode)
二、使用预定义的类
(一)对象与对象变量
new Date()在堆内存中创建了一个新的对象。
声明一个Date d的引用型变量(类似于指针)指向new Date()创建的新的对象,则d是这个对象的对象变量
一个对象变量并没有实际包含一个对象,仅仅是引用一个对象。(可以有多个对象变量指向同一个对象)
使用变量:
1.构造对象
2.指定初始状态
3.对对象应用方法
(二)类方法
构造器ctor:构造新的实例,初始化对象。通常希望构造的对象可以多次使用,所以将对象放在对象变量中。
更改器setter:对实例域做出修改的方法
访问器getter:仅访问实例域而不进行修改的方法
/**
在控制台中打印出台历,要求给今天的日期后加*
Sun Mon Tue Wed Thu Fri Sat
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23*
24 25 26 27 28 29 30
31
需求:
1日历需要知道当前时区定义第一天是周几,比如周日还是周一
GregorianCalendar: getFirstDayOfWeek()
int firstWeekDay=day.getFirstDayOfWeek();
2第一天需要在其所在的星期的位置上,1日之前有多少空格需要确认
通过day.set(Calendar.DAY_OF_MONTH,1)将日期调整到1号,再获取1号的星期int weekday=day.get(Calendar.DAY_OF_WEEK);
计算1号的星期离每周第一天差多少天->得到需要空多少格:
int diff=0;
while(firstWeekDay+diff<weekday){
++diff;
}
3需要将星期排序的缩写打印在第一行
a)DateFormatSymbols中的getShortWeekdays可以返回一周的缩写字符的数组weekName
b)然后将日期调整到本月1号所在那个星期的第一天
day.add(Calendar.DAY_OF_YEAR, -(diff));
c)然后返回第一天的星期,再通过weekName索引得到当日的星期的缩写,通过7次循环得到一周的字符缩写
循环中日期的增加通过day.add(Calendar.DAY_OF_YEAR, 1);实现
4计算本月有多少天
在28日建立一个day的副本,从28号起,每增加一日就和副本进行比较月份,月份不同说明已到下个月,通过差得到一个月的天数
5空格数+当月天数就得到一共需要循环多少次,然后在循环中判断是空格还是1-9日,还是10日以上,分别打印不同的信息。
同时判断本次循环的日期是否是本日,如果是本日则加*
*/
import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
public class TableCalendar {
public static void main(String[] args) {
StringBuilder sb=new StringBuilder();
//now
GregorianCalendar day=new GregorianCalendar();
//now in day & month
int today=day.get(Calendar.DAY_OF_MONTH);
int month=day.get(Calendar.MONTH);
//the first week day of the local timezone
int firstWeekDay=day.getFirstDayOfWeek();
//set day to the 1st day of this month
day.set(Calendar.DAY_OF_MONTH,1);
int weekday=day.get(Calendar.DAY_OF_WEEK);
//get how many blank need
int diff=0;
while(weekday>firstWeekDay+diff){
++diff;
}
//sort the order : weekdays in string
int cnt=0;
String[] weekName=new DateFormatSymbols(Locale.ENGLISH).getShortWeekdays();
day.add(Calendar.DAY_OF_YEAR, -(diff));//get the first "blank" day's weekday
cnt=day.get(Calendar.DAY_OF_WEEK);
//print the weekday String title
for(int i=0;i<7;++i){
//System.out.println(weekName[(firstWeekDay+i)%7]);
sb.append(weekName[cnt]+" ");
day.add(Calendar.DAY_OF_YEAR, 1);
cnt=day.get(Calendar.DAY_OF_WEEK);
}
sb.delete(sb.length()-1, sb.length()).append("\r\n");
//cnt a month have how many days
GregorianCalendar day2=new GregorianCalendar();
day.set(Calendar.DAY_OF_MONTH,28);
day2.set(Calendar.DAY_OF_MONTH,28);
int monthLen=27;
while(day.get(Calendar.MONTH)==day2.get(Calendar.MONTH)){
day2.add(Calendar.DAY_OF_YEAR, 1);
++monthLen;
}
//System.out.println(diff+" "+monthLen);
//print the month
int total=monthLen+diff;
int cntDays=0;
for(int i=1;i<=total;++i){
//blank
if(i<=diff){
sb.append(" ");
//1-9
}else if(i>diff&&i<=diff+9){
sb.append(" "+(++cntDays));
}else{
sb.append(++cntDays);
}
//mark today
if(cntDays==today){
sb.append("* ");
//skip the last day
}else if(cntDays==monthLen){
}else{
sb.append(" ");
}
//newLine
if(0==i%7){
//sb.append("\r\n");
sb.delete(sb.length()-1, sb.length()).append("\r\n");
}
}
System.out.println(sb);
}
}
三、使用自定义类
class ClassName{
field1
field2
ctor1
ctor2
method1
method2
getter
setter
}
一个源文件只能有一个public类,源文件名必须与public类的类名相同
多源文件的使用:
将类的代码单独放置在一个源文件中。
将测试/使用代码放在另一个源文件中。
编译时编译测试代码的源文件即可,当编译器发现使用了某个类会自动搜索其class文件,如果没有则会搜索和编译类的源文件;如果有class文件,但是源文件版本较新,编译器会自动重新编译。
//test.java Seller类虽然不是public,但是仍然可以用,默认权限包内可见
public class test {
public static void main(String[] args) {
Costumer c=new Costumer();
Seller s=new Seller("aaaa");
System.out.println(s);
}
}
//Costumer.java
public class Costumer {
}
class Seller {
private String name;
public Seller(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString() {
return "Seller [name=" + name + "]";
}
}
(一)构造器
ctor总是伴随new操作符的执行被调用,不能对已存在的对象使用ctor(object.ClassName()是错误的)
特点:
1)ctor与类同名
2)每个类可以有多个ctor
3)ctor的参数个数不限
4)ctor没有返回值
5)总伴随new使用
(二)类方法
类的方法通常有两种参数:
隐式参数:出现在方法名前的类对象
显示参数:方法名后的括号中的参数
在每一个方法内部,关键字this表示隐式参数,这样可以将实例域与局部变量明显地区分开。
(三)封装
获取/设置实例域的值:
1一个私有的数据域
2一个公有的域访问器
3一个公有的域更改器
封装优点:
1可以改变内部实现。不影响其他方法
2更改器方法可以进行错误检查
不要编写返回引用可变对象的访问器方法,如果需要返回一个可变对象的引用,应先使用克隆方法(clone()),返回对应可变数据域的一个拷贝。
public Date getDate(){
returnthis.day.clone();
}
(四)基于类的访问权限
基于类的访问权限:一个方法可以访问所属类的所有对象的私有数据。
final实例域:必须在ctor中设置这个final域的值,并在之后,无法再对其进行修改
final修饰符大多应用于基本类型域或者不可变类(类的每个方法都不会改变其对象)的域。
对可变对象使用final并不能保证对象内容不被修改,只能保证引用不变:
private final Date day;//仅仅意味着day这个引用的指向在ctor后不可改变,但是指向的对象的内部的实例域仍然可以通过更改器修改。
四、静态域和静态方法
(一)静态域
静态域:类域,属于类不属于任何独立的对象
实例域:每个对象独立
静态域:所有同类对象所共有
(二)静态常量
静态常量:[public] static final
System.out就是静态常量。不能更改out。但是可以通过setOut()置为其他流。(setOut是本地方法,不是java语言实现的。所以可以绕过final)
(三)静态方法
静态方法:不能向对象实施操作的方法。可以认为静态方法没有this参数。
因为静态方法不能操作对象,所以不能在静态方法中访问实例域。但是静态方法可以访问本类的静态域。
可以使用对象调用静态方法,但是容易让人觉得混乱,应当使用类名调用静态方法
使用静态方法的情况:
1.不需要访问自身对象的状态,其所需参数都是显示参数提供
2.需要访问静态域
(四)工厂方法
工厂方法:通过静态方法产生不同类型的返回对象。
NumberFormatcurrenyFomatter=NumberFormat.getCurrencyInstance();
NumberFormatpercentFomtter=NumberFormat.getPercentInstance();
doublex=0.1;
System.out.println(currencyFormatter.format(x));
System.out.println(percentFormatter.format(x));
(五)main方法
每一个类可以有一个main方法,(因为是静态方法,所以不需要对象,可以在启动时就运行。)每个类设置main()可以用于对类进行单元测试。
运行时java ClassName则调用类内的main进行单元测试;运行时java AppName则调用程序的main方法运行程序。
五、对象构造
重载:相同的方法名,不同的参数列表
方法的签名:方法名+参数类,返回类型不是签名的组成部分e.g. indexOf(int)
调用构造器后的具体处理步骤:
1所有数据域被初始化为默认值(0,false,null)(即是对域赋值为这些默认值)
2按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块(按照顺序执行,比如显示的域值初始化,初始化块)
3若构造器第一行调用了其他构造器,则执行第二个构造器主体(调用this()/super())
4执行这个构造器的主体(执行这个ctor内的代码)
1st默认域初始化:域的值将被初始化为0,false,null
2nd显示域初始化(实例域初始化instance field initialization):在类定义中,直接将一个值赋给任何域,比如:
privateString name=”Alex”;
除了直接赋值。还可以调用方法:
privatestatic int roomId;
privateint newRoomId=genId();
privatestatic int genId(){
inttmp=roomId;
++roomId;
returntmp;
}
3rd初始化块(initialization block)(静态初始化块staticinitialization block/对象初始化块objectinitialization block)
只要构造类对象,初始化块就会被执行。
private int id;
{
id=1;
}
如果静态域赋值的代码比较复杂可以使用静态初始化块
private static int roomId;
static
{
Randomr=new Random();
roomId=r.nextInt(100);
}
域初始化和初始化块在构造器代码之前。
4th ctor中调用另一个ctor:调用另一个ctor必须放在第一行,this(…)/super(…)
ClassName(){
this(“Alex”);
this.age=10;
}
5th
无参数的ctor
带参数的ctor的参数名:应当使用this.name=name这种形式,比较直观。
六、包
一个类可以使用其所属包中的所有类,以及其他包中的public类(一个源文件只能有一个public类)
访问另一个包中公有类的方法:
1在每个类名前添加完整的包名
2导入(类):
import java.util.*;
只能使用一个*。java.*.*是不可以的
类命名冲突时必须使用完整包名
编译器认为嵌套的包之间没有任何关系。java.util包与java.util.jar包相互独立的类集合
静态导入(静态方法和静态类)
import static java.lang.System.*;
import static java.lang.System.out;
将类放入包中:源文件第一行应当是package xxx;
若没有在源文件中写package语句,则将类放置在默认包中。