面向对象编程
Java是一门面向对象的编程,面向对象程序设计的主要概念有抽象、封装、继承、多态。
- 抽象:就是忽略问题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面;
- 封装:一种信息隐蔽技术,就是利用抽象数据类型将数据和基于数据的操作封装在一起;
- 继承:指新的类可以获得已有类(称为基类或父类)的属性和行为,称新类为已有类的派生类(或子类);
- 多态:指一个程序中同名的不同方法共存的情况。
类的声明和引用
每个类都有自己的属性(attribute)和方法(method);比如说时间是有时、分、秒组成,这些是属性;读取时间就是方法。
下面我们创建一个时间类,其中包括时、分、秒;读取时间就是方法。
public class Clock {
//成员变量
int hour;
int minute;
int second;
//成员方法
public void setTime(int newH,int newM,int newS){
hour=newH;
minute=newM;
second=newS;
}
public void showTime(){
System.out.println(hour+":"+minute+":"+second);
}
public static void main(String args[]){
//创建对象
Clock clocks=new Clock();
//调用方法设置时间
clocks.setTime(1,20,40);
//调用方法打印时间
clocks.showTime();
}
}
数据成员
文件Circle.java;
类变量,对于系统中常用的常量值需要声明成静态的,如圆周率。
public class Circle {
static double PI=3.14159265;
int radius;
}
文件Rectangle.java;
public class Rectangle {
double width=10.12;
double height=5.7;
}
文件ShapeTester.java;
public class ShapeTester {
public static void main(String args[]){
Circle x;//实例变量
Rectangle y;
x=new Circle();
y=new Rectangle();
System.out.println(x+" "+y);
System.out.println(x.radius);
System.out.println(y.height);
}
}
@之后的数值为x y所指的对象的存储地址。
输出结果:
Circle@75b84c92 Rectangle@6bc7c054
0
5.7
方法
public class Circle {
static double PI=3.14159265;
int radius;
//声明计算周长的方法
public double circumference(){
return 2*PI*this.radius;
}
}
使用this关键字更明确的说明radius的值从哪里来。由于在类的声明中radius是实例属性,如果在上面的方法中不写关键字this,在程序运行时,Java会自动取其接收者对象的属性值,因此,在这种情况下,关键字this可以省略不写。
public class CircumferenceTester {
public static void main(String args[]){
Circle c1=new Circle();
c1.radius=50;
Circle c2=new Circle();
c2.radius=10;
double circum1=c1.circumference();
double circum2=c2.circumference();
System.out.println("circle 1:"+circum1);
System.out.println("circle 2:"+circum2);
}
}
输出结果:
circle 1:314.159265
circle 2:62.831853
main函数中以public static开头,其中public static就是方法的修饰符。
我们先来了解一下static修饰符,static修饰符可以让方法的使用范围变为全局,如果我们要使用此方法,则不需要创建实例,可以直接使用;
修饰访问权限的关键词则是 public、private、protected。被定义为public的class, attributes, method可以被任何类访问,如果是private那么就无法被其他类访问,protected适用于继承关系间的类,被定义为protected的属性和方法可以被子类访问,父类子类相关的内容我们会在后面详细探讨。
类的组织—包的概念
Java编译器为每一个类生成了一个字节码文件,因此同名的类有可能发生冲突。为了解决类名冲突的问题,Java提供了包机制来管理类名空间。
一般情况下,应将相关的类组织到同一个包中。包主要有以下作用:
1)将相关的源代码文件组织到一起;
2)不同包中的类名可以相同,从而可以避免名字冲突;
3)提供包一级的疯长及存取权限;
一个Java的编译单元,由以下三部分组成:
- 所属包的声明(省略,则属于默认包);
- import(引入)包的声明,用于倒入外部的类;
- 类和接口的声明;
包与目录:
一个包可以包含若干个类文件,还可包含若干个包。由于Java使用文件系统来存储包和类,类名就是文件名,包名就是文件夹名,即目录名。
引入包;
import PackageName;
为了使用其他包中所提供的类,需要使用import语句引入所需要的类。
类成员的访问控制;
在声明一个类时,主要考虑以下几个方面;
- 尽量使用简单;
- 易于维护;
- 只向其他类展示必要的信息。好的编程方法一般不允许其他类直接存取或修改一个对象的实例变量。
类成员的访问控制
- public(公有的):用public修饰的成分表示是公有的,也就是它可以被其他任何对象访问(前提是类成员所在的类有访问的权限);
- private(私有的):类中限定为private的成员只能被这个类本身访问,在类外不可见;
- protected(保护的):用该关键字修饰的成分是受保护的,只可以被同一类及其子类的实例对象访问;
- 无修饰(默认的):public、private、protected这三个限定符不是必须写的。如果不写,则表明“friendly”,相应的成分可以被所包在包中的各类访问。
程序示例;
public class Circle {
static double PI=3.14159265;
private int radius;
public double circumference(){
return 2*PI*this.radius;
}
}
编译的时候会提示错误;
java: radius 在 Circle 中是 private 访问控制
由于在Circle类声明变量radius被声明为private,因此在其他类中不能直接对radius进行存取。
如果要允许其他类访问radius的值,就需要在Circle类中声明相应的公有方法。通常有两类典型的方法用于访问属性值,这两类方法是get方法及set方法。
get方法
get方法的功能是取得属性变量的值。为了便于记忆和阅读,get方法名以get开头,后面是实例变量的名字。get方法一般具有以下格式;
public <fieldType>get<FieldName>(){
return <fieldName>;
}
对于实例变量radius,声明其get方法;
public int getRadius(){
return radius;
}
set方法
set方法的功能是修改属性变量的值。为了便于记忆和阅读,set方法名以“set”开头,后面是实例变量的名字。set方法一般具有以下格式;
public void set<FieldName>(<fieldType><paramName>){
<fieldName>=<paramName>;
}
声明实例变量radius得set方法如下;
public void setRadius(int r){
radius=r;
}
关键字this的使用
如果形式参数名与实例变量名相同,则需要在实例变量名之前加上this关键字;否则系统会将实例变量当成形式参数。
在上面的set方法中,如果形式参数为radius,则需要在成员变量radius之前加上关键字this。
public class Circle {
static double PI=3.14159265;
int radius;
public void setRadius(int radius){
this.radius=radius;
}
public double circumference() {
return 2*PI*radius;
}
public static void main(String args[]){
Circle c1=new Circle();
c1.setRadius(1);
Circle c2=new Circle();
c2.setRadius(10);
double circum1=c1.circumference();
double circum2=c2.circumference();
System.out.println("circle 1:"+circum1);
System.out.println("circle 2:"+circum2);
}
}
输出:
circle 1:6.2831853
circle 2:62.831853
对象和初始化
系统在生成对象时,会为对象分配内存空间,并自动调用构造方法对实例变量进行初始化,当对象不再使用时,系统会调用垃圾回收程序将其占用的内存回收。
构造方法
构造方法是一种特殊的方法。Java中每个类都有构造方法,用来初始化该类的一个新的对象。构造方法具有和类名相同的名称,而不返回任何数据类型。系统在产生对象时会自动执行。
1、系统提供默认的构造方法;
默认的构造方法没有参数,其方法体为空。
class BankAccount{
String ownerName="Tom";
int accountNumber;
float balance;
}
public class BankTester {
public static void main(String args[]){
BankAccount myAccount=new BankAccount();
System.out.println("ownerName="+myAccount.ownerName);
System.out.println("accountNumber="+myAccount.accountNumber);
System.out.println("balance="+myAccount.balance);
}
}
输出:
ownerName=Tom
accountNumber=0
balance=0.0
2、自定义构造方法与方法重载;
在生成对象的时候给构造方法传送初始值,使用希望的值给对象初始化,效果会更好,这就需要自定义构造方法。
class BankAccount{
String ownerName;
int accountNumber;
float balance;
public BankAccount(String initName,int initAccountNumber,float initBalance){
ownerName=initName;
accountNumber=initAccountNumber;
balance=initBalance;
}
public BankAccount(String initName,int initAccountNumber){
ownerName=initName;
accountNumber=initAccountNumber;
balance=0.00f;
}
}
public class BankTester {
public static void main(String args[]){
BankAccount myAccount=new BankAccount("Tom",1000,2000.00f);
System.out.println("ownerName="+myAccount.ownerName);
System.out.println("accountNumber="+myAccount.accountNumber);
System.out.println("balance="+myAccount.balance);
BankAccount myAccount1=new BankAccount("Bob",10000);
System.out.println("ownerName="+myAccount1.ownerName);
System.out.println("accountNumber="+myAccount1.accountNumber);
System.out.println("balance="+myAccount1.balance);
}
}
输出:
ownerName=Tom
accountNumber=1000
balance=2000.0
ownerName=Bob
accountNumber=10000
balance=0.0
Java允许多个方法具有相同的名字。在不同的类中可以声明相同的方法名;在同一个类中也可以声明相同的方法名,但需要具有不同的参数表(参数的个数和类型不同)。
如果一个类中有两个及以上同名的方法,但参数表不同,这种情况就被称为方法重载。在方法调用时,Java可以通过参数列表的不同来辨别调用哪一个方法。
3、自定义无参的构造方法和this关键字;
在声明构造方法时,好的声明习惯是:或者不声明构造方法,如果声明构造方法,通常至少声明两个构造方法,其中一个为无参构造方法。
class BankAccount{
String ownerName;
int accountNumber;
float balance;
public BankAccount(){
this("",9999,0.0f);
}
public BankAccount(String initName,int initAccountNumber){
this(initName,initAccountNumber,0.0f);
}
public BankAccount(String initName,int initAccountNumber,float initBalance){
ownerName=initName;
accountNumber=initAccountNumber;
balance=initBalance;
}
}
public class BankTester {
public static void main(String args[]){
BankAccount account1=new BankAccount();
account1.ownerName="wangli";
BankAccount account2=new BankAccount("Tom",1234,100.00f);
BankAccount account3=new BankAccount("Bob",12345);
System.out.println("ownerName="+account1.ownerName);
System.out.println("accountNumber="+account2.accountNumber);
System.out.println("balance="+account3.balance);
}
}
使用this关键字在一个构造方法中调用另外的构造方法,从而使代码更简洁,维护起来更容易。
内存回收技术
当执行构造方法生成一个对象时,需要占用各种系统资源。当生成的对象不再使用时,就需要返回给操作系统,以免资源泄漏。在各种系统资源中,最常用的就是内存。Java运行时系统通过垃圾收集器周期性的释放无用对象所使用的内存。
c语言通过free来释放内存,c++则通过delete来释放内存,如果程序员忘记释放内存,则容易造成内存泄漏甚至导致内存耗尽。在Java中不会发生内存泄漏情况,但对于其他资源,则有可能产生泄漏的可能性。
Java中的每一个类都有一个finalize()方法用于释放资源,在对对象进行自动垃圾回收前,Java运行时系统会自动调用度喜庆的finalize()方法来释放系统资源,如关闭打开文件或socket等。
该方法的声明格式如下;
protected void finalize() throws throwable
finalize方法在类java.lang.Object中声明,但并没有做任何事情。如果一个类需要释放内存以外的资源,则需要在类中重写finalize()方法。