第七章 面向对象 总结

目录

1.类的封装

2.类的继承:

1.extends关键字

3.方法的重写

super关键字

Object类——所有类的父类

1.getClass()方法

2.toString()方法

 3.equals()方法

4.类的多态

向上转型:子类转变成父类类型

向下转型:父类转变成子类 使用强制转换

instanceof关键字

ExampleClass:某个类

5.抽象类与接口

接口的声明及实现:

多重继承

区分抽象类与接口

6.访问控制

访问控制符

java类包

package 包名;

final关键字

7.内部类:

1.成员内部类

内部类向上转型为接口

 使用this关键字获取内部类与外部类的引用:

局部内部类:

匿名内部类

静态内部类:用static 修饰的类

内部类的继承:


1.类的封装


封装将类的某些信息隐藏在类内部,不允许外部程序直接访问,只能通过该类提供的方法来实现对隐藏信息的操作和访问。例如:一台计算机内部极其复杂,有主板、CPU、硬盘和内存, 而一般用户不需要了解它的内部细节,不需要知道主板的型号、CPU 主频、硬盘和内存的大小,于是计算机制造商将用机箱把计算机封装起来,对外提供了一些接口,如鼠标、键盘和显示器等,这样当用户使用计算机就非常方便。

封装的特点:
 
只能通过规定的方法访问数据。
隐藏类的实例细节,方便修改和实现。
实现封装的具体步骤如下:
 
修改属性的可见性来限制对属性的访问,一般设为 private。
为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写。
在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)。

 例:去饭馆点菜

public class Restaurant1 {//创建一个类
 
	public static void main(String[] args) {//主方法
		String cookName="Tom Cruise";//厨师的名字叫Tom Cruise
		System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
		System.out.println(cookName+"切葱花");//输出
		System.out.println(cookName+"洗蔬菜");//输出
		System.out.println(cookName+"开始烹饪"+"香辣肉丝");//输出
		System.out.println("**请问厨师叫什么名字?***");//输出
		System.out.println(cookName);//输出
		System.out.println("请让厨师给我切一点葱花。***");//输出
		System.out.println(cookName+"切葱花");//输出
	}
 
}

运行结果如下:

public class Restaurant3 {//创建一个类
public static void main(String[] args) {//主方法
		Cook2 cook=new Cook2();//创建厨师类的对象
		System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
		cook.cooking("香辣肉丝");//厨师烹饪香辣肉丝
		System.out.println("**你们的厨师叫什么名字?***");//输出
		System.out.println(cook.name);//厨师回答自己的名字
		System.out.println("**请让厨师给我切一点葱花。***");//输出
		cook.cutOnion();//厨师去切葱花
		}
}
class Cook2{//创建类
	private String name;//厨师的名字
	public Cook2(){//定义方法
		this.name="Tom Cruise";//厨师的名字叫Tom Cruise
	}
	private void cutOnion(){//厨师切葱花
		System.out.println(name+"切葱花");//输出信息
		}
	private void washVegetables(){//厨师洗蔬菜
		System.out.println(name+"洗蔬菜");//输出信息
	}
	void cooking(String dish){//厨师烹饪顾客点的菜
		
		washVegetables();//调用方法
		cutOnion();//调用方法
		System.out.println(name+"开始烹饪"+dish);//输出信息
		}
}

运行结果如下:

public class Restaurant4 {//创建类
private Cook2 cook=new Cook2();//餐厅封装的厨师类
public void takeOlder(String dish){//下单	Restaurant2 a=new Restaurant2();//创建一个对象
	cook.cooking(dish);//通知厨师做菜
	System.out.println("您的菜好了,请慢用。");//输出信息
}
public String saySorry(){//拒绝顾客请求
	return"抱歉,餐厅不提供此项服务。";//返回字符串
	
}
	public static void main(String[] args) {//主方法
		Restaurant4 water=new Restaurant4();//创建餐厅对象,为顾客提供服务
		System.out.println("**请让厨师为我做一份香辣肉丝。***");//输出
		water.takeOlder("香辣肉丝");//服务员给顾客下单
		System.out.println("**你们的厨师叫什么名字?***");//输出信息
		System.out.println(water.saySorry());//服务员给顾客善意的答复
		System.out.println("**请让厨师给我切一点葱花。***");//输出信息
		System.out.println(water.saySorry());//服务员给顾客善意的答复
	}
 
}

 运行结果如下:

 新建狗

package boketask;

public class dog {
	public void find(String  target) {//寻找,目标是 target
		System.out.println("狗饿了,闻着味儿:" +target);//输出函数
	}
	public void run () {//奔跑
		System.out.println("狗跑去了食堂。");
	}
	public boolean catchPrey(String prey) {//捕捉食物,返回捕捉是否成功
		System.out.println("狗开始找食物    找到了——" +prey);
		return true;//返回成功
	}
		public void eat(String food) {//吃食物,参数是food
			System.out.println("狗吃" +food);
		}
		public void sleep() {
			System.out.println("狗睡觉");
		}
		public static void main(String[] args) {
			dog dog1 = new dog();
		    dog1.find("香喷喷的肉");
		dog1.run();
		dog1.catchPrey("一坨屎");
		dog1.eat("shi");
		dog1.sleep();
		
		}
		
	}

运行结果如下:

2.类的继承:

 继承在面向对象开发思想中是一个非常重要的概念,它使整个程序具有一定的弹性,在程序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性。

继承其基本思想是基于某父类的扩展,制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类中的某些方法。

1.extends关键字

在java中,让一个类继承另一个类,用extends关键字

child extends parents//子类继承父类
注意:java中的类只支持单继承,即一个子类只能继承一个父类,类似下面的代码是错误的:

child extends parents1,parent2{
//错误的继承语法
}

注意:java中的类只支持单继承,即一个子类只能继承一个父类,类似下面的代码是错误的:

class Computer{//父类
	String screen="液晶显示屏";
	void startup(){//开机方法
		System.out.println("电脑正在开机,请等待...");//输出
	}
}
 
public class Pad extends Computer{//创建一个类并继承父类
String battery="5000毫安电池";//子类独有的属性
	public static void main(String[] args) {//主方法
		Computer pc=new Computer();//电脑类
		System.out.println("computer的屏幕是:"+pc.screen);//输出
		pc.startup();//调用父类方法
		Pad ipad=new Pad();//平板电脑类
		System.out.println("pad的屏幕是:"+ipad.screen);//子类可以直接使用父类属性
		System.out.println("pad的屏幕是:"+ipad.battery);//子类独有的属性
		ipad.startup();//子类可以直接使用父类方法
 
	}
 
}

运行结果如下:

 从这个结果可以看出,Pad类继承了Computer类之后,虽然没有定义任何成员方法,但仍然可以调用父类的方法,这个方法就是从父类那里继承过来的。 

3.方法的重写

继承并不只是扩展父类的功能,还可以重写父类的成员方法。重写(还可以称为覆盖)就是在子类中将父类的成员方法的名称保留。重新编写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型 (重写父类成员方法的返回值是基于J2SE 5.0版本以上的编译器提供的新功能)。

在继承中还有一种特殊的重写方式,子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容,这种特殊重写方式被称为重构。

注意:当重写父类的方法时,修改方法的修饰权限只能从小的范围到大的范围改变,例如,父类中的doSomething()方法的修饰权限为protected,继承后子类中的方法doSomething()的修饰权限只能修改为public,不能修改为private。

class Computer2{//父类:电脑
	void showPicture(){//定义一个方法
		System.out.println("鼠标单击");//输出信息
	}
}
public class Pad2 extends Computer2 {//创建一个类并继承父类
void showPicture(){//重写父类的方法
	System.out.println("手指点击触摸屏");//输出信息
}
	public static void main(String[] args) {//主方法
		Computer2 pc=new Computer2();//电脑类
		System.out.print("pc打开图片:");//输出信息
		pc.showPicture();//调用方法
		Pad2 ipad=new Pad2();//平板电脑类
		System.out.print("ipad打开图片:");//输出信息
		ipad.showPicture();//重写父类方法
		Computer2 computerpad=new Pad2();//父类声明,子类实现
		System.out.print("computerpad打开图片:");//输出信息
		computerpad.showPicture();//调用父类方法,实现子类重写的逻辑
	}
 
}

运行结果如下:

注意:在java语言中,一个类只可以有一个父类!

super关键字

super关键字可以调用父类的方法和属性,它的使用方法和this关键字相似。但this关键字代表本类的对象,super关键字带调用的是父类的方法

super.property;//调用父类的属性
super.method();//调用父类的方法
class Computer3{//父类:电脑
	String sayHello(){//定义一个方法
		return"欢迎使用";//返回一个字符串
	
	}
	
}
public class Pad3 extends Computer3 {//子类:平板电脑
	String sayHello(){//重写方法
		 return super.sayHello()+"平板电脑";//调用父类方法,在其结果后添加字符串
	}
 
	public static void main(String[] args) {//主方法
Computer3 pc=new Computer3();//电脑类
System.out.println(pc.sayHello());//调用父类的方法并输出
Pad3 ipad=new Pad3();//平板电脑类
System.out.println(ipad.sayHello());//调用子类的方法并输出
 
	}
 
}
 

运行结果如下:

注意:如果在子类构造方法中使用类似super()构造方法,其他初始化代码只能写在super()之后,不能写在前面,否则会报错。 

Object类——所有类的父类

在java中,所有的类都直接或间接继承了java.lang.Object类。Object类是所有类的父类,是java类层中的最高层类。

注意:Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。

1.getClass()方法

getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName ()方法可以取得类的名称。

getClass().getName();//调用getClass()里的getName()方法
可以将getClass()方法与toString()方法联合使用。

2.toString()方法

toString()方法的功能是将一个对象返回为字符串形式,它会返回一个String实例。在实际的应用中通常重写toString()方法。
 

public class ObjectInstance {创建类
public String toString(){//重写toString()方法
	return "在"+getClass().getName()+"类中重写toString()方法";//返回值
}
	public static void main(String[] args) {//主方法
		System.out.println(new ObjectInstance());//调用方法并输出,打印本类对象
	}
 
}

运行结果如下:

 3.equals()方法

比较两个对象的实际内容。 

class V{//自定义类V
	
}
public class OverWriteEquals {//创建一个方法
 
	public static void main(String[] args) {//主方法
		String s1="123";//实例化两个对象,内容相同
		String s2="123";//实例化对象
		System.out.println(s1.equals(s2));//使用equals()方法
		V v1=new V();//实例化两个V类对象
		V v2=new V();//实例化对象
		System.out.println(v1.equals(v2));//使用equals()方法
	}
 
}
 

运行结果如下:

4.类的多态

类的多态性指“一种定义,多种实现”,类的多态性可以从两方面 体现:方法的重载,类的上下转型。

 方法的重载:重载(不需要继承):返回参数不同、传入参数不同、  方法名相同

public class OverLoadTest {//定义一个方法
	public static int add(int a){//定义一个方法并传入一个int型参数
		return a;//返回一个整型值
	}
	public static int add(int a,int b){//定义一个方法并传入两个参数
		return a+b;//返回a+b的值
	}
	public static double add(double a,double b){//定义一个方法并传入两个参数
		return a+b;//返回a+b的值
	}
	public static int add(int a,double b){//定义一个方法并传入两个参数
		return (int)(a+b);//返回a+b的值,同时利用强制转换成int型
	}
	public static int add(double a,int b){//定义一个方法并传入两个参数
		return (int)(a+b);//返回a+b的值,同时利用强制转换成int型
	}
	public static int add(int...a){//定义一个不定长参数方法
		int s=0;//定义一个int型变量并赋予初值
		for(int i=0;i<a.length;i++){//遍历数组
			s+=a[i];//总计
		}
		return s;//返回s的值
	}
	public static void main(String[] args) {//主方法
		System.out.println("调用add(int)方法:"+add(1));//调用方法并输出
		System.out.println("调用add(int,int)方法:"+add(1,2));//调用方法并输出
		System.out.println("调用add(double,double)方法:"+add(2.1,3.3));//调用方法并输出
		System.out.println("调用add(int a,double b)方法:"+add(1,3.3));//调用方法并输出
		System.out.println("调用add(double a,int b)方法:"+add(2.1,3));//调用方法并输出
		System.out.println("调用add(int...a)不定长参数方法:"+add(1,2,3,4,5,6,7,8,9));//调用方法并输出
		System.out.println("调用add(int...a)不定长参数方法:"+add(2,3,4 ));//调用方法并输出
 
	}
 
}

运行结果如下:

 注意:虽然在方法的重载中可以使两个方法的返回类型不同,但只有返回类型不同不足以区分两个方法的重载,还需要通过参数的个数以及参数的类型来设置。

向上转型:子类转变成父类类型

class Quadrangle{//四边形类
public static void draw(Quadrangle q){//四边形类中的方法
//SomeSentence
}
}
public class Parallelogram extends Quadrangle{//平行四边形类,继承了四边形类
public static void main(String args[]){//主方法
Parallelogram p=new Parallelogram();//实例化平行四边形类对象引用
draw(p);//调用父类方法
}
}

运行无结果。

向下转型:父类转变成子类 使用强制转换

class Quadrangle{//父类
	public static void draw(Quadrangle q){//父类方法
		//SomeSentence
	}
}
public class Parallelogram extends Quadrangle {//子类继承父类
 
	public static void main(String[] args) {//主方法
	draw(new Parallelogram());//调用方法并传入子类对象
	Quadrangle q=new Parallelogram();//将平行四边形对象看作是四边形对象,称为向上转型操作
	Parallelogram p=q;//向下转型
 
	}
 
}

运行结果如下:

instanceof关键字

当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生classcastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例。

myobject instanceof ExampleClass//判断是否为该类的实例对象


 myobject:某类的对象引用。

ExampleClass:某个类

使用instanceof操作符的表达式返回值为布尔值。

class Quadrangle{//类名
	public static void draw(Quadrangle q){//构造一个方法并传入一个参数
		//SomeSentence
	}
}
class Square extends Quadrangle{//构造一个类并继承另一个类
	//SomeSentence
}
class Anything{//构造一个类
	//SomeSentence
}
public class Parallelogram extends Quadrangle {//创建一个类并继承另一个类
 
	public static void main(String[] args) {//主方法
		Quadrangle q=new Quadrangle();//创建一个对象
		if(q instanceof Parallelogram){//判断该对象是否属于该类
			Parallelogram p=(Parallelogram)q;//进行强制转换
		}
		if(q instanceof  Square){//判断该对象是否属于该类
			Square s=(Square) q;//进行强制转换
		}
		System.out.println(q instanceof  Anything );//输出信息
	}
 
}

运行结果如下:

5.抽象类与接口


如果一个方法使用 abstract 来修饰,则说明该方法是抽象方法,抽象方法只有声明没有实现。需要注意的是 abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中。

抽象方法的 3 个特征如下:

抽象方法没有方法体
抽象方法必须存在于抽象类中
子类重写父类时,必须重写父类所有的抽象方法

抽象类与抽象方法:在java中设置抽象类不可以实例化对象。
如果一个方法使用 abstract 来修饰,则说明该方法是抽象方法,抽象方法只有声明没有实现。需要注意的是 abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中。

抽象方法的 3 个特征如下:

抽象方法没有方法体
抽象方法必须存在于抽象类中
子类重写父类时,必须重写父类所有的抽象方法

 注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。

[权限修饰符] abstract class 类名{
类体
}
 使用abstract关键字定义的类称为抽象类,而使用abstract关键字定义的方法称为抽象方法。

[权限修饰符]abstract 方法返回值类型 方法名(参数列表);
从上面的语法可以看出,抽象方法是直接以分号结尾的,它没有方法体,抽象方法本身没有任何意义。除非它被重写,而承载这个抽象方法的抽象类必须被继承。

注意:构造方法不能定义为抽象方法

public abstract class Market {//创建类
public String name;//商场名称
public String goods;//商品名称
public abstract void shop();//抽象方法,用来输出信息
	
 
}
public class TaobaoMarket extends Market {//创建类并继承商场类
 
	@Override
	public void shop() {//重写方法
		// TODO Auto-generated method stub
		System.out.println(name+"网购"+goods);	//输出信息	
	}
 
}
public class GoShopping {//类名
 
	public static void main(String[] args) {//主方法
		// TODO Auto-generated method stub
Market market=new WallMarket();//向上转型
market.name="沃尔玛";//赋值
market.goods="七匹狼西服";//赋值
market.shop();//调用方法
market=new TaobaoMarket();//创建一个对象
market.name="淘宝";//赋值
market.goods="韩都衣舍花裙";//赋值
market.shop();//调用方法
	}
 
}

运行结果如下:

使用抽象类和抽象方法时,需要遵守以下原则:

1、在抽象类中,可以包含抽象方法,也可以不包含抽方法,但是包含了抽象方法的类必须被定义为抽象类。

2、抽象类不能直接实例化,即使抽象类中没声明抽象方法,也不能实例化。

3、抽象类被继承后,子类需要实现其中所有的抽象方法。

4、如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。

接口的声明及实现:

接口是抽象类的延申,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。即全部都是抽象方法。抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。

定义接口:

public 表示接口的修饰符,当没有修饰符时,则使用默认的修饰符,此时该接口的访问权限仅局限于所属的包;
interface_name 表示接口的名称。接口名应与类名采用相同的命名规则,即如果仅从语法角度来看,接口名只要是合法的标识符即可。如果要遵守 Java 可读性规范,则接口名应由多个有意义的单词连缀而成,每个单词首字母大写,单词与单词之间无需任何分隔符。
extends 表示接口的继承关系;
interface1_name 表示要继承的接口名称;
constant_name 表示变量名称,一般是 static 和 final 型的;
returnType 表示方法的返回值类型;
parameter_list 表示参数列表,在接口中的方法是没有方法体的。

[修饰符]interface 接口名[extends 父接口名列表]{
[public] [static] [final]常量;
[public] [abstract] 方法;
}

一个类实现一个接口可以使用implements关键字 

public class Parallelogram extends Quadrangle implements drawTest{
....//
}

说明:在接口中定义的任何变量都自动是static和final的,因此,在接口中定义变量时,必须进行初始化,而且,实现接口的子类不能对接口的变量重新赋值。

接口对于其声明、变量和方法都做了许多限制,这些限制作为接口的特征归纳如下:

具有 public 访问控制符的接口,允许任何类使用;没有指定 public 的接口,其访问将局限于所属的包。
方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)。
在 Java 接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化。
接口没有构造方法,不能被实例化。

 

interface drawTest{//定义接口
	public void draw();//定义方法
}
class ParallelogramgleUseInterface implements drawTest{//创建类并继承接口
 
	@Override
	public void draw() {//重写方法
		// TODO Auto-generated method stub
		System.out.println("平行四边形.draw()");//输出
	}
	
}
class SquareUseInterface implements drawTest{//创建类并继承接口
 
	@Override
	public void draw() {//重写方法
		// TODO Auto-generated method stub
		System.out.println("正方形.draw()");//输出
	}
	
}
public class QuadrangleUseInterface {//创建类
 
	public static void main(String[] args) {//主方法
		// TODO Auto-generated method stub
		drawTest[]d={//定义一个一维数组
				new SquareUseInterface(),new ParallelogramgleUseInterface()};//向上转型
		for(int i=0;i<d.length;i++){//遍历数组
			d[i].draw();//输出元素
		}
 
	}
 
}

运行结果如下:

 说明:由于接口中的方法都是抽象的,因此,当子类实现接口时,必须实现接口中所有的方法。

多重继承

  多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承。有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需要思考的不是怎么使用多重继承,而是您的设计是否存在问题.但有时候我们确实是需要实现多重继承,而且现实生活中也真正地存在这样的情况,比如遗传:我们即继承了父亲的行为和特征也继承了母亲的行为和特征。可幸的是Java是非常和善和理解我们的,它提供了两种方式让我们曲折来实现多重继承:接口和内部类。

区分抽象类与接口

 抽象类与接口是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力。他们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别。  尽管抽象类和接口之间存在较大的相同点,甚至有时候还可以互换,但这样并不能弥补他们之间的差异之处。下面将从语法层次和设计层次两个方面对抽象类和接口进行阐述。

6.访问控制


访问控制符

 
在 Java 语言中提供了多个作用域修饰符,其中常用的有 public、private、protected、final、abstract、static、transient 和 volatile,这些修饰符有类修饰符、变量修饰符和方法修饰符。

通过使用访问控制修饰符来限制对对象私有属性的访问,可以获得 3 个重要的好处。

防止对封装数据的未授权访问。
有助于保证数据完整性。
当类的私有实现细节必须改变时,可以限制发生在整个应用程序中的“连锁反应”。

 访问控制符是一组限定类、属性或方法是否可以被程序里的其他部分访问和调用的修饰符。类的访问控制符只能是空或者 public,方法和属性的访问控制符有 4 个,分别是 public、 private、protected 和 friendly,其中 friendly 是一种没有定义专门的访问控制符的默认情况。

1. private

用 private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用。因此,private 修饰符具有最高的保护级别。例如,设 PhoneCard 是电话卡类,电话卡都有密码,因此该类有一个密码域,可以把该类的密码域声明为私有成员。

2. friendly(默认)

如果一个类没有访问控制符,说明它具有默认的访问控制特性。这种默认的访问控制权规定,该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类。这种访问特性又称为包访问性(package private)。

同样,类内的成员如果没有访问控制符,也说明它们具有包访问性,或称为友元(friend)。定义在同一个文件夹中的所有类属于一个包,所以前面的程序要把用户自定义的类放在同一个文件夹中(Java 项目默认的包),以便不加修饰符也能运行。

3. protected

用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类。使用 protected 修饰符的主要作用,是允许其他包中它的子类来访问父类的特定属性和方法,否则可以使用默认访问控制符。

4. public

当一个类被声明为 public 时,它就具有了被其他包中的类访问的可能性,只要包中的其他类在程序中使用 import 语句引入 public 类,就可以访问和引用这个类。

说明:
类中被设定为 public 的方法是这个类对外的接口部,避免了程序的其他部分直接去操作类内的数据,实际就是数据封装思想的体现。每个 Java 程序的主类都必须是 public 类,也是基于相同的原因。

java类包

在编写 Java 程序时,随着程序架构越来越大,类的个数也越来越多,这时就会发现管理程序中维护类名称也是一件很麻烦的事,尤其是一些同名问题的发生。有时,开发人员还可能需要将处理同一方面的问题的类放在同一个目录下,以便于管理。

包允许将类组合成较小的单元(类似文件夹),它基本上隐藏了类,并避免了名称上的冲突。包允许在更广泛的范围内保护类、数据和方法。你可以在包内定义类,而在包外的代码不能访问该类。这使你的类相互之间有隐私,但不被其他世界所知。

包的 3 个作用如下:

区分相同名称的类。
能够较好地管理大量的类。
控制访问范围。
Java 中使用 package 语句定义包,package 语句应该放在源文件的第一行,在每个源文件中只能有一个包定义语句,并且 package 语句适用于所有类型(类、接口、枚举和注释)的文件。定义包语法格式如下:

package 包名;

Java 包的命名规则如下:

包名全部由小写字母(多个单词也全部小写)。
如果包名包含多个层次,每个层次用“.”分割。
包名一般由倒置的域名开头,比如 com.baidu,不要有 www。
自定义包不能 java 开头。

注意:如果在源文件中没有定义包,那么类、接口、枚举和注释类型文件将会被放进一个无名的包中,也称为默认包。在实际企业开发中,通常不会把类定义在默认包下。
 

包导入
如果使用不同包中的其它类,需要使用该类的全名(包名+类名)。代码如下:
example.Test test = new example.Test();
 
其中,example 是包名,Test 是包中的类名,test 是类的对象。
 
为了简化编程,Java 引入了 import 关键字,import 可以向某个 Java 文件中导入指定包层次下的某个类或全部类。import 语句位于 package 语句之后,类定义之前。一个 Java 源文件只能包含一个 package 语句,但可以包含多个 import 语句。
 
使用 import 导入单个类的语法格式如下:
import 包名+类名;
 
上面语句用于直接导入指定类,例如导入前面的 example.Test 类,代码如下:
import example.Test;
 
使用 import 语句导入指定包下全部类的用法按如下:
import example.*;
 
上面 import 语句中的星号(*)只能代表类,不能代表包,表明导入 example 包下的所有类。
系统包
Java SE 提供了一些系统包,其中包含了 Java 开发中常用的基础类。在 Java 语言中,开发人员可以自定义包,也可以使用系统包,常用的系统包如表 1 所示。
 
表1 Java中常用的系统包
包	说明
java.lang	Java 的核心类库,包含运行 Java 程序必不可少的系统类,如基本数据类型、基本数学函数、
字符串处理、异常处理和线程类等,系统默认加载这个包
java.io	Java 语言的标准输入/输出类库,如基本输入/输出流、文件输入/输出、过滤输入/输出流等
java.util	包含如处理时间的 Date 类,处理动态数组的 Vector 类,以及 Stack 和 HashTable 类
java.awt	构建图形用户界面(GUI)的类库,低级绘图操作 Graphics 类、图形界面组件和布局管理
(如 Checkbox 类、Container 类、LayoutManger 接口等),以及用户界面交互控制和事
件响应(如 Event 类)
java.awt.image	处理和操纵来自网上的图片的 Java 工具类库
java.wat.peer	很少在程序中直接用到,使得同一个 Java 程序在不同的软硬件平台上运行
java.net	实现网络功能的类库有 Socket 类、ServerSocket 类
java.lang.reflect	提供用于反射对象的工具
java.util.zip	实现文件压缩功能
java.awt.datatransfer	处理数据传输的工具类,包括剪贴板、字符串发送器等
java.sql	实现 JDBC 的类库
java.rmi	提供远程连接与载入的支持
java. security	提供安全性方面的有关支持
读者现在只需对这些包有一个大致印象即可,随着教程后面的介绍,读者会逐渐熟悉它们的用法。

final关键字

final 在 Java 中的意思是最终,也可以称为完结器,表示对象是最终形态的,不可改变的意思。final 应用于类、方法和变量时意义是不同的,但本质是一样的,都表示不可改变,类似 C# 里的 sealed 关键字。

使用 final 关键字声明类、变量和方法需要注意以下几点:

final 用在变量的前面表示变量的值不可以改变,此时该变量可以被称为常量。
final 用在方法的前面表示方法不可以被重写(子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写,又称为方法覆盖。这里了解即可,教程后面我们会详细讲解)。
final 用在类的前面表示该类不能有子类,即该类不可以被继承。
final 修饰变量
final 修饰的变量即成为常量,只能赋值一次,但是 final 所修饰局部变量和成员变量有所不同。
final 修饰的局部变量必须使用之前被赋值一次才能使用。
final 修饰的成员变量在声明时没有赋值的叫“空白 final 变量”。空白 final 变量必须在构造方法或静态代码块中初始化。
注意:final 修饰的变量不能被赋值这种说法是错误的,严格的说法是,final 修饰的变量不可被改变,一旦获得了初始值,该 final 变量的值就不能被重新赋值。

final class FinalClass {//创建类
	int a=3;//定义一个整型变量并赋予初值
	void doit(){//定义一个方法
	}
	public static void main(String[] args) {//主方法
		// TODO Auto-generated method stub
FinalClass f=new FinalClass();//创建对象
f.a++;//调用成员变量并进行自增运算
System.out.println(f.a);//输出
	}
 
}
 

 运行结果如下:

 final方法:定义为final的方法不能被重写。

class Parents{//类名
	private final void doit(){//方法
		System.out.println("父类.doit()");//输出
	}
	final void doit2(){//方法
		System.out.println("父类.doit2()");//输出
	}
	public void doit3(){//方法
		System.out.println("父类.doit3()");//输出
	}
}
class Sub extends Parents{//创建类并继承父类
	public final void doit(){//方法
		System.out.println("子类.doit()");//输出
	}
//	final void doit2(){//方法
	//	System.out.println("父类.doit2()");
		
	//}
	public void doit3(){//方法
		System.out.println("子类.doit3()");//输出
	}
}
public class FinalMethod {//创建类
 
	public static void main(String[] args) {//主方法
		// TODO Auto-generated method stub
Sub s=new Sub();//创建对象
s.doit();//调用方法
Parents p=s;//执行向上转型操作
//p.doit();//不能调用private方法
p.doit2();//调用方法
p.doit3();//调用方法
	}
 
}

运行结果如下:

 final变量:final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该量的值。通常,有final定义的变量为常量

final关键字定义的变量必须在声明时对其进行赋值操作。final除了可以修饰基本数据类型的常量,还可以修饰对象引用。由于数组也可以被看作一个对象来引用,所以final可以修饰数组。一旦一个对象引用被修饰为final后,它只能恒定指向一个对象,无法将其改变以指向另一个对象。一个既是static又是final的字段只占据一段不能改变的存储空间。为了深入了解final关键字,来看下面的实例:
 

import java.util.Random;//导入random方法
import static java.lang.System.out;//导入方法
 
class Test{//类名
	int i=0;//定义一个整型变量并初始化
}
public class FinalData {//创建类
static Random rand=new Random();//创建对象
private final int VALUE_1=9;//定义常量
private static final int VALUE_2=10;//定义常量
private  final Test test=new Test();//创建对象
private Test test2=new Test();//创建对象
private final int[]a={1,2,3,4,5,6};//定义一个一维数组并赋值
private final int i4=rand.nextInt(20);//定义变量并随即赋值
private static final int i5=rand.nextInt(20);//定义变量随机赋值
public String toString(){//使用toString()方法
	return i4+" "+i5+" ";//返回字符串
}
	public static void main(String[] args) {//主方法
	FinalData data=new FinalData();//创建对象
	data.test=new Test();//创建对象
	data.VALUE_2;//调用变量
	data.test2=new Test();//向上转型
for(int i=0;i<data.a.length;i++){//遍历数组
	//a[i]=9;
	//不能对定义为final的数组赋值
}
out.println(data);//输出
out.println("data2");//输出
out.println(new FinalData());//输出
out.println(data);//输出
	}
}

运行结果如下:

import java.util.Random;//导入Random方法
import static java.lang.System.out;//导入方法
 
public class FinalStaticData {//创建类
private static Random rand=new Random();//实例化一个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的值:"+fdata.a1);//输出
		out.println("重新实例化对象调用a1的值:"+fdata.a2);//输出
		FinalStaticData fdata2=new FinalStaticData();//创建对象
		out.println("重新实例化对象调用a1的值:"+fdata2.a1);//输出
		out.println("重新实例化对象调用a2的值:"+fdata2.a2);//输出
	}
 
}

 运行结果如下:

7.内部类:

内部类的特点如下:

内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。


1.成员内部类

在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。
 
内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。
 
内部类可以分为:实例内部类、静态内部类和成员内部类,每种内部类都有它特定的一些特点,本节先详细介绍一些和内部类相关的知识。
 
在类 A 中定义类 B,那么类 B 就是内部类,也称为嵌套类,相对而言,类 A 就是外部类。如果有多层嵌套,例如类 A 中有内部类 B,而类 B 中还有内部类 C,那么通常将最外层的类称为顶层类(或者顶级类)。

public class OuterClass{//外部类
private class InnerClass{//内部类
//...
}
}

 在内部类可以随意使用外部类的成员方法以及成员变量。

public class OuterClass {//创建类
innerClass in=new innerClass();//创建对象
public void ouf(){//方法
	
}
class innerClass{//类名
	innerClass(){//方法
		
	}
	public void inf(){//方法
	}
	int y=0;//定义变量
	}
	public innerClass doit(){//方法
		//y=4;
		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();//向上转型
 
	}
 
}

无运行结果

内部类向上转型为接口

interface OutInterface{//定义接口
	public void f();//抽象方法
}
public class InterfaceInner {//创建类
 
	public static void main(String[] args) {主方法
		OuterClass2 out=new OuterClass2();//创建对象
		OutInterface outinter=out.doit();//调用方法
		outinter.f();//调用方法
	}
}
class OuterClass2{//类名
	private class InnerClass implements OutInterface{//继承接口
InnerClass(String s){//重写方法
	System.out.println(s);//输出
}
		
		public void f() {//重写方法
			System.out.println("访问内部类中的f()方法");//输出信息
		}
		
	}
	public OutInterface doit(){//重写方法
		return new InnerClass("访问内部类构造方法");//输出信息
		
	}
}

运行结果如下: 

 使用this关键字获取内部类与外部类的引用:

public class TheSameName {//类名
private int x;//定义整型变量
private class Inner{//定义方法
	private int x=9;//定义整型变量并初始化
	public void doit(int x){//方法
		x++;//自增运算
		this.x++;//自增运算
		TheSameName.this.x++;//自增运算
	}
}
}

无运行结果

局部内部类:

内部类不仅可以在类中进行定义,也可以在类的局部位置定义。

interface OutInterface2{//定义接口
	
}
	
 class OuterClass3 {//类名
public OutInterface2 doit(final String x){//方法
	class InnerClass2 implements OutInterface2(String s){类继承
		InnerClass2(String s){//内部类
			
		s=x;//赋值
		System.out.println(s);//输出
	}
	
}
	return new InnerClass2("doit");//返回值
}
}

无运行结果

匿名内部类

匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下: 

匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:
 
new <类或接口>() {
    // 类的主体
};
interface OutInterface2{//定义一个接口
}
class OuterClass4{//创建类
public OutInterface2 doit(){//定义方法
return new OutInterface2(){//返回值
private int i=0;//定义变量并初始化
public int getValue(){//方法
return i;//返回值
}
};
}
}
return new A(){
...//内部类体
};

使用匿名内部类时应该遵循以下原则:
(1)匿名类没有构造方法;
(2)匿名类不能定义静态的成员;
(3)匿名类不能用private、public、protected、static、final、abstract等修饰;
(4)只可以创建一个匿名类实例。

静态内部类:用static 修饰的类

静态内部类具有以下两个特点:

(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
 

public class StaticInnerClass {//创建类
	int x=100;//定义一个整型变量并初始化
	static class Inner{//内部类
	void doitInner(){//方法
	//System. out. printin("外部类"+x);//输出
	}
	public static void main(String args[]){//主方法
	
	
	System. out. println();//换行
	}
}
}

无运行结果

内部类的继承:

public class OutputInnerClass extends ClassA.ClassB{//创建类并继承另一个类
public OutputInnerClass(ClassA a){//方法
a.super();//调用父类构造方法
}
}
class ClassA{//外部类
class ClassB{//内部类
}
}

无运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值