1、类的封装
将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。比如,我们到餐厅去点餐,我们创建一个餐厅的对象,同时创建一个厨师的对象,用户可以进行点餐,然后就可以吃饭,但没办法知道厨师的具体信息,以及厨师如何做这道菜的。代码实现如下:
public class Resturant {
Cook cook = new Cook();
public void takeOrder(String dish){
cook.cooking(dish);
System.out.println("您的"+dish+"做好了,请慢用");
}
public String saySorry(){
return "抱歉,本餐厅不提供此项服务";
}
public static void main(String[] args){
Resturant res = new Resturant();
System.out.println("请帮我做一份香辣肉丝");
res.takeOrder("香辣肉丝");
System.out.println("你们的厨师叫什么名字");
System.out.println(res.saySorry());
}
}
class Cook {
private String name;
public Cook(){
this.name = "Tom Cruise";
}
private void cutUnion(){
System.out.println(this.name + "切葱花");
}
private void washVegetables(){
System.out.println(this.name + "洗蔬菜");
}
void cooking(String dish){
this.washVegetables();
this.cutUnion();
System.out.println(this.name + "开始烹饪" + dish);
}
}
输出为:
请帮我做一份香辣肉丝
Tom Cruise洗蔬菜
Tom Cruise切葱花
Tom Cruise开始烹饪香辣肉丝
您的香辣肉丝做好了,请慢用
你们的厨师叫什么名字
抱歉,本餐厅不提供此项服务
2、类的继承
继承的基本思想就是基于某个父类的扩展,制定出一个新的子类,子类集成父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类的某些方法。例如平行四边形是特殊的四边形,可以说平行四边形继承了四边形类,这是平行四边形类将四边形类的所有属性和方法都保留了下来,并基于四边形类扩展了一些新的属性和方法。
接下来,我们介绍继承的四个小的知识点
extends关键字
在java中,让一个类继承另一个类,用extends实现
方法的重写
重写就是在子类中将父类的成员方法的名称保留,重新编写成员方法的实现内容,更改成员方法的存储权限或者修改成员方法的返回值类型。
值得注意的一点是,修改方法的修饰权限时,只能从小变大,比如父类的权限是protected,那么子类的权限只能是public。
super关键字
如果子类重写了父类的方法,如果想调用父类的方法,可以使用super关键字。
同样,在构造函数中,使用super关键字可以调用父类的构造方法,而子类构造方法中的其他代码只能写在super之后。
在类的继承机制中,当实例化子类对象时,父类对象也相应被实例化,也就是说,会自动调用父类的无参构造方法,但是有参构造方法不能被调用,只能依赖于super关键字。
下面,我们基于一个例子来体会下上面所介绍的内容:
public class Pads extends Computer{
String sayHello(){
return super.sayHello() + "平板电脑";
}
public static void main(String[] args){
Computer pc = new Computer();
System.out.println(pc.sayHello());
Pads pad = new Pads();
System.out.println(pad.sayHello());
}
}
class Computer{
String sayHello(){
return "欢迎使用";
}
}
输出为:
欢迎使用
欢迎使用平板电脑
object类
在java中,所有类都直接或者间接继承了java.lang.Object类,它是所有类的父类,在Object类中,有几个比较重要的方法:
getClass().getName() : 该方法可以得到类的名称。
toString():toString()方法的功能是将一个对象返回为字符串形式。
equals():在object类中,equals方法实现的是==的功能,即比较两个对象的引用地址,所以如果想让equals方法比较的是对象的内容的话,需要对该方法进行重写。
3、类的多态
多态意为一个名字可具有多种语义,类的多态性可以从两个方面来体现:一是方法的重载,二是类的上下转型。
方法的重载:方法的重载就是在一个类中允许同时存在一个或者多个以上的同名方法,只要这些方法的参数个数或类型不同即可。方法的重载与方法的重写的区别要注意区分,重写指的是子类继承父类时,重新实现父类中的非私有方法。
如下面的代码,我们定义了多个add方法,由于add方法的参数类型、参数个数、参数顺序不同,都构成了方法的重载。
public class OverLoadTest {
public static int add(int a) {
return a;
}
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, double b) {
return (int) (a + b);
}
public static double add(double a, double b) {
return a + b;
}
public static int add(double a, int b) {
return (int) (a + b);
}
public static int add(int... a) {
int s = 0;
for (int i : a) {
s += i;
}
return s;
}
}
向上转型
向上转型指把子类对象直接赋值给父类类型的变量,如定义一个四边形类Quadrangle和一个平行四边形类Parallelogram:
Quadrangle q = new Parallelogram()
与向上转型相对应的是向下转型,即把一个父类对象直接赋值给子类类型的变量,这往往是不可以的,正如平行四边形都是四边形,但不是四边形都是平行四边形一样,这样做是有危险的,我们需要显式强制转换才可以。
isinstanceof关键字
可以使用isinstanceof操作符来一个类是否是某个类的实例。
4、抽象类和接口
4.1 抽象类
通常说四边形具有4条边,或者更具体一点,平行四边形是具有对边平行且相等的特性的特殊的四边形,等腰三角形是其中两条边相等的三角形,但对于一般的图形对象,我们很难使用具体的语言去描述,它有几条边,究竟是什么图形,没有人能说清楚,这种类在java中被定义为抽象类。
使用abstract关键字定义的类称为抽象类,而使用abstract关键字定义的方法称为抽象方法。
在使用抽象类和抽象方法时,必须遵循下面的原则:
1)抽象类中,可以包含或者不包含抽象方法,但是包含抽象方法的类必须是抽象类。
2)抽象类不能直接被实例化
3)抽象类被继承后,子类需要实现其中所有的抽象方法
4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
下面是一个抽象类的代码:
public class goShopping {
public static void main(String[] args){
Market market = new WallMarket();
market.name = "沃尔玛";
market.goods = "七匹狼西服";
market.shop();
market = new TaoBaoMarket();
market.name = "淘宝";
market.goods = "韩都衣舍花裙";
market.shop();
}
}
abstract class Market{
public String name;
public String goods;
public abstract void shop();
}
class TaoBaoMarket extends Market{
@Override
public void shop() {
System.out.println(name + "网购" + goods);
}
}
class WallMarket extends Market{
@Override
public void shop() {
System.out.println(name + "实体店购买" + goods);
}
}
输出为:
沃尔玛实体店购买七匹狼西服
淘宝网购韩都衣舍花裙
4.2 接口声明及实现
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中所有方法都没有方法体,接口使用interface关键字进行定义。而接口继承接口时,使用extends关键字,而类继承接口时,使用的是implements关键字。这里要注意区分。当子类实现接口时,必须实现接口中所有的方法。另外一点需要注意的是,接口中所有的变量都是static和final的,所以必须进行初始化,而实现接口的子类不能对接口中的变量进行重新赋值。
下面是一个接口的举例:
public class QuadrangleUseInterface {
public static void main(String[] args){
drawTest[] d = {new SquareUseInterface(),new ParallelogramgleUseInterface()};
for(int i=0;i<d.length;i++){
d[i].draw();
}
}
}
interface drawTest{
public void draw();
}
class ParallelogramgleUseInterface implements drawTest{
@Override
public void draw() {
System.out.println("平行四边形.draw()");
}
}
class SquareUseInterface implements drawTest{
@Override
public void draw() {
System.out.println("正方形.draw()");
}
}
输出为:
正方形.draw()
平行四边形.draw()
可以看到,接口同样适用向上转型。
4.3 抽象类和接口的区别
1)子类只能继承一个抽象类,但可以继承多个接口。
2)一个类要实现一个接口必须要实现接口中的所有方法,但是抽象类只用实现抽象方法。
3)抽象类中的成员变量可以是各种类型,但是接口中的成员变量只能是public static final
4)接口中只能定义抽象方法,但是抽象类中可以定义非抽象方法
5)抽象类中可以有静态方法和静态代码块,接口中不可以
6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法
5、访问控制
java中的访问控制符主要有public、protected、default、private,那么这四种访问控制符的访问权限如下表所示:
public | protected | default | private | |
---|---|---|---|---|
本类 | 可见 | 可见 | 可见 | 可见 |
本类所在包 | 可见 | 可见 | 可见 | 不可见 |
其他包中的子类 | 可见 | 可见 | 不可见 | 不可见 |
其他包中的非子类 | 可见 | 不可见 | 不可见 | 不可见 |
6、final关键字
定义为final的类不能被继承
final的方法不能被重写
用final声明的变量不能被改变,也就是说final声明的变量可以认为是常量。但这个常量是相对于一个对象来说的,要想使一个变量变为真正的常量,也就是对所有对象来说,其值都是一样的,应该定义为static final,如下面的例子中,两个对象的a1值是不一样的,但是a2是一样的。
import java.util.Random;
import static java.lang.System.out;
public class FinalStaticData {
private static Random rand = new Random();
private final int a1 = rand.nextInt(10);
private static final int a2 = rand.nextInt(10);
public static void main(String[] args){
FinalStaticData fdata = new FinalStaticData();
out.println("a1_value" + fdata.a1);
out.println("a2_value" + fdata.a2);
FinalStaticData fdata1 = new FinalStaticData();
out.println("a1_value" + fdata1.a1);
out.println("a2_value" + fdata1.a2);
}
}
输出为:
a1_value3
a2_value6
a1_value0
a2_value6
7、内部类
如果类中再定义一个类,那么类中再定义的那个类被称为内部类,比如汽车和发动机的关系。内部类可以分为成员内部类、局部内部类和匿名类。
7.1 成员内部类
在成员内部类中,内部类可以随意使用外部类的成员方法以及成员变量,但是内部类的成员只有在内部类的范围之内的可知的,不能被外部类使用。内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现。
public class OuterClass {
innerClass in = new innerClass();
public void ouf(){
in.inf();
}
class innerClass{
innerClass(){
}
public void inf(){
}
int y = 0;
}
public innerClass doit(){
in.y = 4;
return new innerClass();
}
public static void main(String[] args){
OuterClass out = new OuterClass();
OuterClass.innerClass in = out.doit();
OuterClass.innerClass in2 = out.new innerClass();
}
}
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。下面的例子中,x是形参,this.x代表内部类的x,TheSameName.this.x++代表了外部类的成员变量x:
public class TheSameName {
private int x = 5;
private class Inner{
private int x = 9;
public void doit(int x){
System.out.println(x) ;
System.out.println(this.x);
System.out.println(TheSameName.this.x++);
}
}
public static void main(String[] args){
TheSameName tsn = new TheSameName();
TheSameName.Inner inner = tsn.new Inner();
inner.doit(2);
}
}
输出为:
2
9
5
7.2 局部内部类
内部类不仅可以在类中进行定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类。
interface OutInterface2{
}
public class OuterClass3 {
public OutInterface2 doit(final String x){
class InnerClass2 implements OutInterface2{
InnerClass2(String s){
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
7.3 匿名内部类
使用如下的语法创建内部类:
return new A(){
//内部类体
}
7.4 静态内部类
在内部类堑添加修饰符static,这个内部类就变为静态内部类了,一个静态内部类中可以声明静态成员,但是在非静态内部类中不可以声明静态成员。静态内部类中不能使用外部类的非静态成员,所以静态内部类在程序开发中比较少见。