以Java为例,阐释面向对象的特点
封装
private最能体现封装的特点,使外部不能随便访问
public class Fengzhuang
{
public static void main(String args[])
{
Person p1=new Person();
p1.setSno(99001);
System.out.println (p1.getSno());
p1.setSno("99001x");
System.out.println (p1.getSno());
}
}
class Person
{
//情况例子:本来是数字,后来想改成String
//private int sno;
//变为
private String sno;
//sno面向外部的接口
/*public int getSno()
{
return sno;
}*/
//变为
public String getSno()
{
return sno;
}
public void setSno(int sno)
{
this.sno=sno+"";
}
public void setSno(String sno)
{
this.sno=sno;
}
}
重载和重写
重载利用了方法可以有不同种类和数量的特性:方法名相同但参数的种类和数量不完全相同。注:返回值不同不叫重载。
重写:子类对父类方法的重写,子类重写一个与父类方法名字和参数序列都相同的方法。返回值类型必须相同,如果父类方法返回值类型是对象类型,子类重写方法的返回值可以是父类方法返回值的子类。
父类中的final方法不能重写。
可以直接通过子类对象调用父类的方法(方法未在子类中被重写)
注:重写方法权限不能比父类方法访问权限低(如父类位public,子类为默认为不可以的)
如果访问权限和返回值类型都不相同,仅名字相同,则不构成重写
构成重写的异常抛出问题,父类的方法抛出的异常必须能包含子类方法抛出的异常(但调用子类方法所在的方法抛异常类型与父类抛出的异常类型无关),父类抛子类不抛也是可以的。
import java.io.IOException;
public class Fengzhuang
{
public static void main(String args[]) throws IOException
{
Son s=new Son();
s.kk();
}
}
class Person
{
public void kk() throws Exception
{
System.out.println ("Person kk");
}
}
class Son extends Person
{
/*对重写方法:
*子类方法抛异常父类方法必须抛,且要把子类方法的异常包含在内(子类抛出的异常必须比父类更严谨、仔细)
*父类方法有异常对子类方法没有限制
*调用子类方法所在的位置要抛的异常种类与父类方法抛出的异常没有关系,只与子类有关系
**/
public void kk() throws IOException//重写父类的方法
{
System.out.println ("Son kk");
return ;
}
}
多态
父类引用指向子类对象:Father f = new Son();
多态的作用:借用子类中重写的父类的方法(抽象类和接口中被覆盖的方法),仅包括方法,不包括变量
可以用抽象类或接口的引用指向其子类的引用,从而可以使用抽象类或接口中被覆盖的方法,变量则还会使用父类中的值
public class Fengzhuang
{
/*多态:父类引用指向子类对象
*可以在某些方面解决接口或抽象类无法实例对象(只能有引用)的问题
**/
public static void main(String args[])
{
Son s=new Son();
System.out.println (s.x+s.y);//若子类中没有名字和父类相同的元素,会直接使用父类中的元素
Father f=s;//父类引用指向子类对象
f.kk();//方法看对象
f=new Son2();
f.kk();
System.out.println (f.y+";"+f.s);//成员变量看引用,用的是父类的变量,输出9;0(用的是父类的值)
FF ff=f;
ff.kk();
System.out.println (ff.x);//输出0
}
}
abstract class FF
{
/*
*可以用抽象类或接口的引用指向其子类的引用,
*从而可以使用抽象类或接口中被覆盖的方法,
*变量则还会使用父类中的值*/
int x=0;
abstract void kk();
}
class Father extends FF
{
int x=6;//若子类中没有出现名字类型相同的
int y=9;
String s="0";
public void kk()
{
System.out.println ("father.kk");
}
}
class Son extends Father
{
long y=19;
String s="1";
public void kk()
{
System.out.println ("Son .kk");
}
}
class Son2 extends Father
{
long y=199;
String s="2";
public void kk()
{
System.out.println ("Son2 .kk");
}
}
重载
同一个类中,名字相同,参数序列不同的方法。返回值不同不构成重载。一个类中不能存在名字和参数序列都相同的两个方法,即使返回值不同。
构造器
和类名相同,没有返回类型,可带参数,在每次new 对象时执行,只是引用时不会调用
没有构造其实,系统会自动生成空参构造器,但如果自己写了带参的,则不会自动生成再空参的
public class Gouzao
{
//构造器
public static void main(String args[])
{
new SS();
/*输出:Father
Son
SS
生成子类对象时,会先走父类的构造器(空参),
然后再走自己的构造器。*/
new SSSS();
/*当父类没有空参构造器时,直接继承会报错,
*要在子类构造器中调用父类的带参构造器super(int x,....);
*因为默认子类构造器中存在且在第一行有super();
*
*或者写this();调用自己的构造器。(适用于有空参构造器,并且有多个构造器(重载)的)
**/
}
}
class Father
{
public Father()
{
System.out.println ("Father");
}
}
class Son extends Father
{
public Son()
{
System.out.println ("Son");
}
}
class SS extends Son
{
public SS()
{
System.out.println ("SS");
}
}
class SSS extends SS
{
public SSS(int a)
{
System.out.println ("SSS");
}
}class SSSS extends SSS
{
public SSSS()
{
super(5);
System.out.println ("SSSS");
}
public SSSS(int a)
{
//super(5);
this();
System.out.println ("SSSS");
}
}
静态成员,非静态成员,构造器在创建对象时的执行顺序
public class OO
{
//构造器
/*静态成员变量也会先走父类的
*静态的会最先执行
*类成员和构造器在同一等级,看先后位置决定执行顺序,先父后子
**/
public static void main(String args[])
{
new Son();
/*输出:父类静态
子类静态
父类构造器
子类构造器*/
/*输出:父类静态
子类静态
父类非静态
父类构造器
子类非静态
子类构造器*/
}
}
class Father
{
Pr p2=new Pr("父类非静态成员变量");
static Pr p1=new Pr("父类静态成员变量");
public Father()
{
System.out.println ("父类构造器");
}
}
class Son extends Father
{
Pr p2=new Pr("子类非静态成员变量");
static Pr p1=new Pr("子类静态成员变量");
public Son()
{
System.out.println ("子类构造器");
}
}
class Pr
{
public Pr(String s)
{
System.out.println (s);
}
}
返回类型
方法的返回类型只能低于声明的返回类型(声明父类,返回子类)