0 前言
计算机程序的发展经历了面向过程到面向对象的转变。如何理解面向过程和面向对象呢?我们以做一个盒子的例子说明:
面向过程:不去想做什么样子的盒子,随即取工具制作,然后慢慢做成想要的样子;
面向对象:先想好做一个什么样的盒子,搭好整体框架,再去找对应的工具去做细节。
简单来说,面向对象就是建立在更符合人类思维的、更抽象的客观世界模型上来解决问题的。我们知道,客观世界是由许多不同种类的对象组成的,每一个对象都有各自的运动规律和内部状态,且不同对象之间相互联系、相互作用。为了减少程序的冗余,增强逻辑性和管理,我们将同属性的对象归类,在类中定义对象的属性、方法,然后再通过调用,按照不同对象的特点去实例化对象、对象属性和方法。
再用一个例子来理解上面这段话:比如一个教室里有很多学生,每一个学生都有名字、性别、年龄等属性,学生最关注的是成绩,可以按成绩排出及格、优秀、差等生三类。在这个例子中,学生属于类,单个学生就是对象,而名字、姓名、年龄属于对象的属性;按照成绩排等级属于对象的一种方法。
这样,就建立了类、对象、方法的概念了。
面向对象技术以基本对象模型为单位,将对象内部的细节封装在模型中,重视对象模块间的接口联系和对象与外部环境之间的关系。就好比我们买来一个电视机,这个电视机的操作就是一个面向对象的设计,我们不需要管电视机是怎么设计、内部原理是怎么运行的,只需要知道它与外界的交互关系(也就是上面的按钮怎么操作)即可。
从这个角度来看,面向对象存在抽象性、封装性、继承、多态性等特征。
1 类、对象和方法的创建及使用
在面向对象的程序中,首先要声明对象的类,并通过实例化的方式构造对象,然后赋予对象属性和方法。
(1)类的创建格式
类是用来创建对象的模板,定义对象的共同特征,包括数据和操作。例如,猫、狗、鸡等属于对象,他们虽然外形不同,但都属于同一类——动物类,因此,可以创建动物这个类,来涵盖这些个对象。
类的语法结构包括关键字class和跟在后面的类名称。如果要继承自某个类,还需要用extends关键字,关于继承部分内容后面会详细给出。
类创建的格式如下:
class 类名称{
属性
方法
}
例如:
class Person{
String name;
int age;
public void tell(){
System.out.Println(name+age);
}
}
在这个例子中,class是类关键字,Person是类名; name、age是对象属性,tell是对象方法(该方法用于输出姓名和年龄)。这便创建了一个类。
(2)对象的创建格式
上文提到,声明对象的类后,需要在主程序中通过实例化操作来创建对象。对象的创建格式为:
类名称 对象名=new 类名称()
例如:
Person per=null;//声明
per=new Person();//实例化
也可以用一句代码直接实例化
Person per = new Person();//实例化
其中,new是实例化操作的关键字,用于开辟堆空间,存放具体内容。在刚创建的时候per里面存放的是空(null)。
总结而言,要获得一个类的对象需要两步,其一,必须声明该类类型的一个变量,也就是上述代码中的per,第二部,声明创建一个对象的实际物理空间存放具体内容,这是通过new运算符来实现的,new运算符为对象动态分配内存空间,并返回对它的一个引用。
(3)对象对属性和方法的调用方式
对象的属性和方法通常在主程序或者类方法中调用,调用格式为:
对象.属性
对象.方法
例如:
public static void main(String[] args) {
Person per=null;//声明
per=new Person();//实例化
per.setName("Sonny");
per.setAge(24);
per.tell();
}
其中,per是实例化创建的对象,per.tell()便是对象per调用的tell方法。
(4)方法
方法是在类中定义,用来实现对象操作的过程或者函数,属于一个给定对象的过程和函数,反应的是对象的行为而不是数据。
其定义格式为:
访问修饰符 返回值类型 方法名(){
方法主体
}
例如:
public void tell(){
System.out.Println(name+age);
}
其中,访问修饰符包括缺省、public、private、protected四种,用于限定可访问性属性
通常方法可分为有返回值和无返回值两种,有返回值的方法必须标明返回值类型,如int 等,没有返回值的必须标明void关键字。
当一个实例变量不是被该实例变量所在类的部分代码访问时,必须通过该对象加点运算符来访问,但是当一个实例变量被定义该变量的类的代码访问时,该变量可以被直接引用,同样的规则也适用于方法。
(5)整体范例
前文讲述了如何创建类、对象和方法的分别创建,但放在一个可运行有实际目的的程序中,应该如何编写呢?下面举一个例子,以使得对该部分内容有一个整体上的认知。
例:
编写并测试一个代表地址的address类,地址信息由国家、省份、城市、区等组成,并可以返回完整的地址信息。
package demo;
class Address{ //声明类,类名为Address
String country;//声明对象属性
String province;
String city;
String strict;
public void addressInfo(){ //声明对象方法
System.out.println(country+province+city+street);
}
}
public static void main(String[] args){//主程序入口
Address ad=new Address();//实例化对象
ad.country="中国";//对象属性赋值
ad.province="湖北";
ad.city="武汉";
ad.strict="洪山"
ad.addressInfo();//调用对象方法
}
补充说明:java程序的注释
在任何程序语言中都存在注释,以方便阅读,java根据功能的不同,注释分为三种:
单行注释——
//
例如:
int num; // 定义一个整数
多行注释——
/*
*/
例如:
/*
int c=10;
int x=5;
*/
文档注释——
/**
*/
2. 封装性
2.1 概述
类的目的是封装复杂性,在类的内部就应该有隐藏实现复杂性机制,类中的每个方法或变量都可以被标记为私有、公共。类的公共接口代表类的外部用户需要知道或可以知道的每件事情;私有方法和数据仅能被一个类的成员代码所访问,其他任何不是类的成员的代码都不能访问私有的方法或变量。
既然类的私有成员仅能被程序中的其他部分通过该类的公共方法访问,那么你就能保证不希望发生的事情一定不会发生。这便是封装。
封装将数据和处理数据的代码链接起来,但同时也提供另一个重要属性:访问控制。通过控制访问,可以阻止对象的滥用。前文已提到过访问修饰符,不再赘述。
(1)封装目的
封装性是为了保护某些属性和方法不被外部所看见
(2)封装的实现
为属性和方法进行封装是通过关键字private声明的,声明后该属性和方法不能被直接调用,而需要使用该属性的set和get方法
package control;
class Person{
private int age;
private String name;
public void tell() {
System.out.println("姓名"+getName()+"年龄"+getAge());
}
public int getAge() {
return age;
}
public void setAge(int a) {
age=a;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
}
public class debugtest {
public static void main(String[] args) {
Person per=null;//声明
per=new Person();//实例化
per.setName("Sonny");
per.setAge(24);
per.tell();
}
}
2.2 构造方法
(1)格式
访问修饰符 类名称(){
程序语句
}
注:没有返回值类型
package control;
class People{
public People() {
System.out.println("hello ,world!");
}
}
public class debugtest {
public static void main(String[] args) {
People per=new People();
}
}
(2)注意点
构造方法也称为构造函数,在对象创建时初始化,其名称必须与类名一致,一旦定义了构造函数,在对象创建后,在new运算符完成前,构造函数立即自动调用。
但是,构造方法没有返回值,即使是void型的值也不返回。构造函数的任务就是初始化一个对象的内部状态,以便使创建的实例变量能够完全初始化。
构造方法主要是为类中的属性初始化
(3)匿名对象的使用
匿名对象是只被使用一次的对象创建方式,例如:
class Student{
public void tell(){
System.out.println("hello , sonny!");
}
public static void main(String[] args){
new Student().tell();
}
3.引用传递
对象变量的赋值和我们直觉上认为的不同,例如:
Box b1=new Box();
Box b2=b1;
在这个例子中,虽然b1赋值给了变量b2,但这个过程没有给b2分配任何内存或对原对象做任何部分的拷贝,b1和b2将引用同一个对象,因此,通过变量b2对对象的改变也将影响b1所对应的对象。
但同时,b1和b2之间没有任何其他的关系。
例如,
Box b1=new Box();
Box b2=b1;
b1=null;
虽然b1被设置为空,但是b2仍然指向原来的对象。
具体见下述内容。
3.1 引用传递
计算机语言给子程序传递参数的方法有两种
一种是按值传递,即将一个参数值复制成为子程序的正式参数,这样,对于子程序的参数改变不影响它的参数;
第二种是引用调用,参数的引用被传递给子程序参数,在子程序中,被引用用来访问调用指定的实际参数。
在java中,方法的参数如果是基本数据类型,参数则采用传值调用;如果是对象数据类型,则采用引用调用。
例如下面的例子:
package exceptionDemo;
public class debugd {
public static void main(String[] args) {
String str1="hello";
System.out.println(str1);
tell(str1);
System.out.println(str1);
}
public static void tell(String str2) {
str2="sonny";
}
}
在这段程序中,最开始str1创建为hello,然后创建str2后,两者同时指向hello,所以上段程序最终结果都是hello。
3.2 this 关键字
有时一个方法需要引用调用它的对象,因此定义了this关键字。this可以在引用当前对象的所有方法内使用,this总是调用该方法对象的一个引用,可以在当前类的类型所允许对象的任何地方将this作为一个引用。
(1)表示类中的属性和调用方法
在同一个范围或一个封装范围内,定义二个重名的局部变量在java中是不合法的,但是局部变量是可以与类的实例变量的名字重叠,在这种情况下,局部变量名就隐藏了实例变量名。
如下面例子:
package exceptionDemo;
class People{
private String name;
private int age;
public People(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 tell() {
System.out.println(getName()+getAge());
}
}
public class debugd {
public static void main(String[] args) {
People p= new People("张三",30);
p.tell();
}
}
(2)调用本类中的构造方法
this 必须放在构造方法的首行
package exceptionDemo;
class People{
private String name;
private int age;
public People(String name, int age) {
this();
this.name =name;
this.age=age;
}
public People() {
System.out.println("wucanshu");
}
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 tell() {
System.out.println(getName()+getAge());
}
}
public class debugd {
public static void main(String[] args) {
People p= new People("张三",30);
p.tell();
}
}
(3)表示当前对象
package exceptionDemo;
class People{
public void tell() {
System.out.println(this);
}
}
public class debugd {
public static void main(String[] args) {
People p= new People();
System.out.println(p);
p.tell();
}
}
3.3 static关键字
有时希望定义一个类成员,使它的使用完全独立于该类的任何对象。我们可以创建这样一个成员,它能够被自己调用,而不必引用特定的实例。在成员的声明语句前面加上关键字static即可创建。
(1)声明属性
该属性为全局属性,如果被定义为static,就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。
(2)声明方法
直接通过类名调用
(3)限制
使用 static方法时,只能访问static声明的属性和方法,而非static声明的属性和方法是不能访问的。
不能以任何方式引用this或super。
(4)例子
class UseStatic{
static int a=3;
static int b;
static void meth(int x){
System.out.println("x="+x);
System.out.println("a="+a);
System.out.println("b="+b);
}
statci{
System.out.println("Statci block initialized.");
b=a+4;
}
public static void main(String args[]){
meth(42);
}
在这个程序中,UseStatic被装载后,所有的static语句被运行,
3.4 递归
java支持递归,即允许方法调用自身调用的属性。
很典型的例子是数字的阶乘,例如:
class Factorial{
int fact(int n){
int result;
if (n==1) return 1;
result = fact(n-1)*n;
return result;
}
}
class Recursion{
public static void main(String args[]){
Factorial f=new Factorial();
System.out.println("Factorial of 3 is "+ f.fact(3));
System.out.println("Factorial of 4 is "+ f.fact(4));
System.out.println("Factorial of 5 is "+ f.fact(5));
}
4 继承性
5. 抽象类和接口
5.1 final 关键字
final关键字在java中被称为完结器,表示最终的意思
final能声明类、方法、属性:
(1)使用final 声明的类不能被继承;
(2)使用final声明的方法不能被重写;
(3)使用final声明的变量变成常量,常量是不可以被修改的。
例如:
final class People{
public void final tell(){
}
class Student extends People{
public void tell(){
}
}
public class FinalDemo01
public static void main(String[] args){
fianl String NAME="Sonny";
NAME="SONNY";
}
}
当People类创建为final时,Student类将不能继承People
当People类中的tell方法定义为final时,在Student类中不能重写;
当主程序中定义了NAME为final时,此时NAME已经是一个常量,不能被修改。
5.2 抽象类
(1)抽象类概念
包含一个抽象方法的类就是抽象类
(2)抽象方法:
声明而未被实现的方法,抽象方法必须使用abstract关键字声明
(3)抽象类被子类继承,子类(如果不是抽象类)必须重写抽象类中的所有抽象方法。
(4)定义格式
abstract class className{
属性
方法
抽象方法
}
(5)抽象类不能直接实例化,要通过其子类进行实例化
package classdemo
class Abs{
private int age;
public void tell(){
}
//抽象方法
public abstract void say();
}
public class AbsDemo{
public static void main(String[] args){
Abs a= new Abs();
}
}
5.3 接口
(1)接口是java中最重要的概念,可以理解为一种特殊的类,里面全部是由全局变量和公共的抽象方法所组成
(2)接口的格式
interface interfaceName{
全局变量
抽象方法
}
(3)接口的实现也必须通过子类,使用关键字implements,而且接口是可以多实现的。
例如:
interface Inter{
//抽象对象
public static final int AGE=100;
//抽象方法、
public abstract void tell();
}
class A implements Inter{
public void tell(){
}
}
public class InterDemo01{
public static void main(String[] args){
A a=new A();
a,tell();
System,out.println(Inter,AGE);
}
}
6 面向对象的多态性
(1)概述
多态性的体现有两种,一种是方法的重载和重写,另一种是对象的多态性
对象的多态性由
向上转型:程序会自动完成
父类 父类对象=子类实例
向下转型:强制类型转换
子类 子类对象=(子类)父类实例
class A{
public void tell1(){
System.out.println("A--tell1");
}
public void tell2(){
System.out.println("A--tell2");
}
}
class B extend A{
public void tell1(){
System.out.println("B--tell1");
}
public void tell3(){
System.out.println("B--tell3");
}
}
public class PolDemo01{
public static void main(String[] args){
//向上转型
B b=new B();
A a=b;
a.tell1();
a.tell2();
//向下转型
A a= new B();
B b=(B)a;
b.tell1();
b.tell2();
}
}
(2)关键字instanceof
在java中可以通过使用instanceof关键字判断一个对象到底是不是一个类的实例。
System.out.println(a instanceof A);
instanceof 的返回值是一个布尔类型。
(3)应用及使用
范例:
abstract class Person{
private int age;
private String name;
public Person(int age, String name){
this.age=age;
this.name=name;
}
public int getAge(){
}
public int setAge(){
}
public String getName(){
}
public String setName(){
}
public Student(int age,String name,int score){
super(age,name);
this.score=scpre;
public void want()
System,out.println(getName+getAge);
}
}
public Worker(int age,String name,int money){
super(age,name);
this.money=money;
public void want()
System,out.println(getName+getAge);
}
}
public class AbsDemo02{
public static void main(String[] args){
Student s=new Student(10,"小明",100);
s.want();
Worker w=new Worker(30,"大明",1000);
w.want();
}
}
注:其中get和set程序书写不完整
7 泛型
(1)泛型的定义
泛型是JDK1.5之后增加的新功能,可以解决数据类型的安全性问题,主要原理是在类声明的时候通过一个标识标识类中某个属性的类型或者某个方法的返回值及参数类型;
(2)格式
访问权限 class 类名称<泛型、泛型…>{
属性
方法
}
(3)对象的创建
类名称<具体类型> 对象名称=new 类名称<具体类型>();
(4)举例
package exceptionDemo;
class Point<T>{
private T x;
private T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
/**
* 经纬度
* int
* float
* @author Administrator
*
*/
public class debugd {
public static void main(String[] args) {
Point<String> p=new Point<String>();
p.setX("10");
p.setY("10");
System.out.println("x="+p.getX()+"y="+p.getY());
}
}