面向对象的编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
类定义了对象长什么样,对象则是按照类的定义所制出来的实体,一个类可以创建很多对象,每个对象都有自己的数据。
创建对象
让对象做事
成员变量
函数与成员变量
this
this是成员函数的一个特殊的固有的本地变量,它表达了调用这个函数的那个对象
调用函数
本地变量
成员变量定义初始化
构造函数(构造器)
函数重载
对象和对象之间的联系紧密程度叫做耦合。对象和对象的耦合程度越紧,表现在源代码上,就是它们的代码是互相依赖、互相牵制的。我们理想的模型,是对象和对象之间的耦合要尽可能的松,平行的对象要尽量减少直接联系,让更高层次的对象来提供通信服务。这些就是在我们这个非常简单的数字钟的例子中所体现的。
Display.Java
package clock;
public class Display {
private int value = 0;
private int limit = 0;
public Display(int limit) {
this.limit = limit;
}
public void increase() {
value++;
if(value == limit) {
value = 0;
}
}
public int getValue() {
return value;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
Clock.Java
package clock;
public class Clock {
private Display hour = new Display(24);
private Display minute = new Display(60);
public void start() {
while(true) {
minute.increase();
if(minute.getValue() == 0) {
hour.increase();
}
System.out.printf("%02d:%02d\n", hour.getValue(),minute.getValue());
}
}
public static void main(String[] args) {
Clock clock = new Clock();
clock.start();
}
}
上述中的代码,表示分钟的对象和表示小时的对象没有直接交互。如果想要做直接交互,让分钟的对象在翻转的时候直接调用表示小时的那个对象的那个increase函数,可以用如下代码:
Display.Java
package jinjie;
public class Display {
private int limit = 0;
private int value = 0;
public Display(int limit){
this.limit = limit;
}
public void increase(Display d) {
value++;
if(value==limit) {
value=0;
if(d!=null) {
d.increase(null);
}
}
}
public int getValue() {
return value;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Display d = new Display(24);
Display m = new Display(60);
while (true) {
m.increase(d);
System.out.printf("%02d:%02d\n",d.getValue(),m.getValue());
}
}
}
封装
封装,就是把数据和对这些数据的操作放在一起,并且用这些操作把数据掩盖起来,是面向对象的基本概念之一,也是最核心的概念。
我们有一个非常直截了当的手段来保证在类的设计的时候做到封装:
所有的成员变量必须是private的,这样就避免别人任意使用你的内部数据;
所有public的函数,只是用来实现这个类的对象或类自己要提供的服务的,而不是用来直接访问数据的。除非对数据的访问就是这个类及对象的服务。简单地说,给每个成员变量提供一对用于读写的get/set函数也是不合适的设计。
private
只有在这个类的内部可以访问
类的内部指的是类的成员函数和定义初始化
这个限制是对类的而不是对对象的
在访问私有的成员变量时需要用到get/set方法。
public
任何人都可以访问
任何人指的是在任何类的函数或定义初始化中可以使用
使用指的是调用、访问或定义变量
包
当你的程序越来越大的时候,你就会需要有一个机制帮助你管理一个工程中众多的类了。包就是Java的类库管理机制,它借助文件系统的目录来管理类库,一个包就是一个目录,一个包内的所有的类必须放在一个目录下,那个目录的名字必须是包的名字。
作为初学者,你可以忽略不看包,反正一切靠Eclipse。但是作为一个Java程序员,你不能不懂包。要不然,在使用别人的类库和部署你的程序的时候,会遇到不少莫名其妙的麻烦。
类变量/类函数
类是描述,对象是实体。在类里所描述的成员变量,是位于这个类的每一个对象中的。
而如果某个成员有static关键字做修饰,它就不再属于每一个对象,而是属于整个类的了。
通过每个对象都可以访问到这些类变量和类函数,但是也可以通过类的名字来访问它们。类函数由于不属于任何对象,因此也没有办法建立与调用它们的对象的关系,就不能访问任何非static的成员变量和成员函数了。
静态方法只能访问静态变量,静态变量能够被所有的方法访问。
容器是现代程序设计非常基础而重要的手段。所谓容器,就是“放东西的东西”。数组可以看作是一种容器,但是数组的元素个数一旦确定就无法改变,这在实际使用中是很大的不足。一般意义上的容器,是指具有自动增长容量能力的存放数据的一种数据结构。在面向对象语言中,这种数据结构本身表达为一个对象。所以才有“放东西的东西”的说法。
Java具有丰富的容器,Java的容器具有丰富的功能和良好的性能。熟悉并能充分有效地利用好容器,是现代程序设计的基本能力。首先学习的是顺序容器,即放进容器中的对象是按照指定的顺序(放的顺序)排列起来的,而且允许具有相同值的多个对象存在。
例子:记事本
设计要求:
package notebook;
import java.util.ArrayList;
public class NoteBook {
private ArrayList<String> notes = new ArrayList<String>();
public void add(String s) {
notes.add(s);
}
public void add(String s,int location) {
notes.add(location, s);
}
public int grtSize() {
return notes.size();
}
public String getNote(int index) {
return notes.get(index);
}
public void removeNote(int index) {
notes.remove(index);
}
public String[] list(){
String[] a = new String[notes.size()];
notes.toArray(a);
return a;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
NoteBook nb = new NoteBook();
nb.add("first");
nb.add("second");
nb.add("third", 1);
System.out.println(nb.grtSize());
System.out.println(nb.getNote(0));
System.out.println(nb.getNote(1));
nb.removeNote(1);
String[] a = nb.list();
for(String s:a) {
System.out.println(s);
}
}
}
容器类(数组列表)
在java 中有一个叫做ArrayList的类,具有自动调节数组容量的功能。Arraylist是一个采用类型参数的泛型类,为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来加在后面。
ArrayList<String> notes = new ArrayLiat<String>();
容器类有两个类型:
使用add方法可以将元素添加到数组列表中。例如:
notes.add(new String(..,..,..));
如果调用add且内部数组已经满了,数组列表就将自动地创建一个更大的数组,并将所有的对象从较小的数组中拷贝到较大的数组中去。如果已经清楚或者能够估计出数组可能存储的元素数量,就可以在填充数组之前调用ensureCapacity方法:
notes.ensureCapacity(100);
这个方法调用将分配一个包含100个对象的内部数组。然后调用100次add,而不用重新分配空间。另外还可以把初始容量传递给ArrayList构造器:
ArrayList<String> notes = new ArrayList<String>(100);
size方法将返回数组列表中包含的实际元素书目,例如:
notes.size();
将返回notes数组列表的当前元素数量,它等价于数组a的a.length。一旦能够确认数组列表当前的大小不再发生变化,就可以调用trimToSize方法。这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。
访问数组列表元素
数组列表自动扩展容量的便利增加了访问元素语法的复杂程度。例如要设置第i个元素,可以使用:
notes.set(i,harry);
它等价于对数组a的元素赋值:a[i] = harry;
使用下列格式获得数组列表的元素:
String s = notes.get(i);
下面这个技巧既可以灵活的扩展数组又可以方便的访问数组元素。首先创建一个数组,并添加所有的元素。
ArrayList<X> list = new ArrayList<X>();
while(...)
{
x = ...;
list.add(x);
}
执行完上述操作后,使用toArray方法将数组元素拷贝到另一个数组中。
X[] a = new X[list.size()];
list.Array(a);
为了插入一个新元素,位于n之后的所有元素都要向后移动一个位置。如果插入新元素后,数组列表的大小超过了容量,数组列表就会被重新分配存储空间。
notes.add(n,e); //n必须介于0到size()-1之间
同样也可以从数组类表中删除一个元素:
String s = notes.remove(n); //n必须介于0到size()-1之间
所有的基本类型都有一个与之对应的类。例如,Integer类对应着基本类型int。通常这些类成为包装器。这些对象包装器类拥有很明显的名字:Integer,Long,Float,Double,Short,Byte,Character,Void,Boolean(前6个类派生于公共超类Number)。对象包装器是不可变的,一旦构造了包装器就不允许更改包装在其中的值。同时,对象包装器还是final,因此不能定义他们的子类。
包装类的构造方法:
基本类型和包装类之间的对应关系:
包装类的常用方法:
假设想定义一个整型数组列表。而尖括号中的参数类型不允许是基本类型,也就是说不允许写成ArrayList。这里就用到了Integer对象包装器类。我们可以声明一个Integer对象的数组列表。
ArrayList<Integer> list = new ArrayList<>();
装箱:把基本类型转换成包装类,使其具有对象的性质,又可分为手动装箱和自动装箱
int i = 10; //定义一个int基本类型
Integer x = new Integer(i); //手动装箱
Integer y = i; //自动装箱
拆箱:和装箱相反,把包装类对象装换成基本类型的值,又可分为手动拆箱和自动拆箱
Integer j = new Integer(8); //定义一个Integer包装类对象,值为8
int m = j.intValue(); //手动拆箱为int类型
int n = j; //自动拆箱为int类型
对象数组
当数组的元素的类型是类的时候,数组的每一个元素其实只是对象的管理者而不是对象本身。因此,仅仅创建数组并没有创建其中的每一个对象!
集合容器
集合就是数学中的集合的概念:所有的元素都具有唯一的值,元素在其中没有顺序。
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<String> a = new ArrayList<String>();
a.add("first");
a.add("second");
a.add("third");
System.out.println(a);
System.out.println("---------");
HashSet<String> s = new HashSet<String>();
s.add("first");
s.add("second");
s.add("first");
System.out.println(s);
}
散列表(Hash)
传统意义上的Hash表,是能以int做值,将数据存放起来的数据结构。Java的Hash表可以以任何实现了hash()函数的类的对象做值来存放对象。
package notebook;
import java.util.HashMap;
import java.util.Scanner;
public class Coin {
private HashMap<Integer, String> coinnames = new HashMap<Integer, String>();
public Coin() {
coinnames.put(1, "peeny");
coinnames.put(10, "dime");
coinnames.put(25, "quarter");
coinnames.put(50, "half-dolor");
coinnames.put(50, "wumao");
System.out.println(coinnames.keySet().size());
System.out.println(coinnames);
for( Integer k : coinnames.keySet()) {
String s = coinnames.get(k);
System.out.println(s);
}
}
public String getName(int amount) {
if (coinnames.containsKey(amount))
return coinnames.get(amount);
else
return "NOT FOUND";
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int amount = in.nextInt();
Coin coin = new Coin();
String name = coin.getName(amount);
System.out.println(name);
}
}
基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是public还是private。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。
Database.java
package dome;
import java.util.ArrayList;
public class Database {
private ArrayList<CD> listCD = new ArrayList<CD>();
private ArrayList<DVD> listDVD = new ArrayList<DVD>();
public void add (CD cd) {
listCD.add(cd);
}
public void add (DVD dvd) {
listDVD.add(dvd);
}
public void list() {
for(CD cd : listCD) {
cd.print();
}
for(DVD dvd : listDVD) {
dvd.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc","abc",4,60,"...."));
db.add(new CD("def","def",4,60,"...."));
db.add(new DVD("xxx","aaa",60,"....."));
db.list();
}
}
CD.java
package dome;
public class CD {
private String title;
private String artist;
private int numofTracks;
private int playingtim;
private boolean gotIt = false;
private String comment;
public CD(String title, String artist, int numofTracks, int playingtim, String comment) {
super();
this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
this.playingtim = playingtim;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println("CD:"+title+":"+artist);
}
}
DVD.java
package dome;
public class DVD {
private String title;
private String director;
private int playingtim;
private boolean gotIt = false;
private String comment;
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println("DVD:"+title+":"+director);
}
public DVD(String title, String director, int playingtim, String comment) {
super();
this.title = title;
this.director = director;
this.playingtim = playingtim;
this.comment = comment;
}
}
在这里CD和DVD两个类有许多相似的地方,此时就可以利用继承这个特性。在这里创建一个Item的类,让CD和DVD都继承它。代码如下:
Item.java
package dome;
public class Item {
public void print() {
// System.out.println("Item");
}
}
Database.java
package dome;
import java.util.ArrayList;
public class Database {
// private ArrayList listCD = new ArrayList();
// private ArrayList listDVD = new ArrayList();
private ArrayList<Item> listItem = new ArrayList<Item>();
// public void add (CD cd) {
// listCD.add(cd);
// }
// public void add (DVD dvd) {
// listDVD.add(dvd);
// }
public void add(Item item) {
listItem.add(item);
}
public void list() {
// for(CD cd : listCD) {
// cd.print();
// }
// for(DVD dvd : listDVD) {
// dvd.print();
// }
for(Item item : listItem) {
item.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc","abc",4,60,"...."));
db.add(new CD("def","def",4,60,"...."));
db.add(new DVD("xxx","aaa",60,"....."));
db.list();
}
}
CD.java
package dome;
public class CD extends Item{
private String title;
private String artist;
private int numofTracks;
private int playingtim;
private boolean gotIt = false;
private String comment;
public CD(String title, String artist, int numofTracks, int playingtim, String comment) {
super();
this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
this.playingtim = playingtim;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println("CD:"+title+":"+artist);
}
}
DVD.java
package dome;
public class DVD extends Item{
private String title;
private String director;
private int playingtim;
private boolean gotIt = false;
private String comment;
public static void main(String[] args) {
}
public void print() {
// TODO Auto-generated method stub
System.out.println("DVD:"+title+":"+director);
}
public DVD(String title, String director, int playingtim, String comment) {
super();
this.title = title;
this.director = director;
this.playingtim = playingtim;
this.comment = comment;
}
}
我们把用来做基础派生其他类的哪个类叫做父类、超类或者基类,而派生出来的新类叫做子类。
Java用关键字extends表示这种继承/派生关系:
class ThisClass extends SuperClass{
......
}
Java的继承只允许单继承,即一个类只能有一个父类。
父类成员访问属性 | 在父类中的含义 | 在子类中的含义 |
---|---|---|
public | 对所有人开放 | 对所人开放 |
protected | 只有包内其他类、自己和子类可以访问 | 只有包内其它类、自己和子类可以访问 |
缺省 | 只有包内其他类可以访问 | 如果子类与父类在同一个包内:只有包内其它类可以访问。否则:相当于private,不能访问 |
private | 只有自己可以访问 | 不能访问 |
super:
super和this的不同:
子类和子类型
多态变量
造型Cast
造型的特点
向上造型
假设现有4个类:Person、Teacher、Student和PhDStudent。Teacher 和Student都是Person的子类,PhDStudent是Student的子类。以下的赋值语句哪些是合法的
1 | Person p1 = new Student(); | √ |
---|---|---|
2 | Person p2 = new PhDStudent(); | √ |
3 | PhDStudent phd1 = new Student(); | |
4 | Teacher t1 = new Person(); | |
5 | Student s1 = new PhDStudent(); | √ |
6 | s1 = p1; | |
7 | s1 = p2; | |
8 | p1 = s1; | √ |
9 | t1 = s1; | |
10 | s1 = phd1; | √ |
11 | Phd1 = s1; | |
12 | p1 = p2; | √ |
13 | p2 = p1; | √ |
总结:
//类型之间的转化 : 父---子
//高 低
Person s1 = new Student();
//高转低可以直接转;低转高,需要强制转
//
Student s2 = (Student) s1;
s2.go();
//或((Student) s1).go();
测试实例
public class Person {
public void run(){
System.out.println("run");
}
}
public class Student extends Person{
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student()
//new Person()
//可以指向的引用类型就不确定了:父亲的引用指向了子类
//student能都调用的方法都是自己的或者继承父类的
Student s1 = new Student();
//Person 父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
//对象能执行那些方法,主要看对象左边的类型,和右边的关系不大!
s2.run();//子类重写了父类的方法,执行子类的方法
s1.run();
s1.eat();
s2.eat();
}
}
方法重写 Override
方法名必须相同 参数列表必须相同
修饰符:范围可以扩大,但不能缩小;public > protected > Default >private
抛出的异常: 范围,可以被缩小但不能扩大;ClassNotFoundException <— Exception(大)
重写,子类的方法和父类必须一致,但方法体不同!
为什么需要从写:
父类的功能,子类不一定需要,或者不一定满足!
测试代码:
public class B {
public static void test(){
System.out.println("B->test()");
}
}
public class A extends B{
public static void test(){
System.out.println("A->test()");
}
}
public class Application {
public static void main(String[] args) {
//静态方法:方法的调用智慧和左边的定义的数据类型有关
A a = new A();
a.test();
//父类的引用指向了子类
B b = new A();
b.test();
}
}
public class B {
public void test(){
System.out.println("B->test()");
}
}
public class A extends B{
public void test(){
System.out.println("A->test()");
}
}
public class Application {
public static void main(String[] args) {
//非静态的:重写
A a = new A();
a.test();
//子类重写了父类的方法
B b = new A();
b.test();
}
}
覆盖override
package dome;
public class CD extends Item{
private String artist;
private int numofTracks;
public CD(String title, String artist, int numofTracks, int playingtime, String comment) {
super(title,playingtime,false,comment);
this.artist = artist;
this.numofTracks = numofTracks;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println("CD:");
super.print();
System.out.println(artist+numofTracks);
}
}
DVD.java
package dome;
public class DVD extends Item{
private String director;
public DVD(String title, String director, int playingtime, String comment) {
super(title,playingtime,false,comment);
this.director = director;
}
public static void main(String[] args) {
DVD dvd = new DVD("a","b",1,"...");
dvd.print();
}
public void print() {
System.out.println("DVD:");
super.print();
System.out.println(director);
}
}
Database.java
package dome;
import java.util.ArrayList;
public class Database {
// private ArrayList listCD = new ArrayList();
// private ArrayList listDVD = new ArrayList();
private ArrayList<Item> listItem = new ArrayList<Item>();
// public void add (CD cd) {
// listCD.add(cd);
// }
// public void add (DVD dvd) {
// listDVD.add(dvd);
// }
public void add(Item item) {
listItem.add(item);
}
public void list() {
// for(CD cd : listCD) {
// cd.print();
// }
// for(DVD dvd : listDVD) {
// dvd.print();
// }
for(Item item : listItem) {
item.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc","abc",4,60,"...."));
db.add(new CD("def","def",4,60,"...."));
db.add(new DVD("xxx","aaa",60,"....."));
db.list();
}
}
Item.java
package dome;
public class Item {
private String title;
private int playingtime;
private boolean gotIt = false;
private String comment;
public Item() {
}
public Item(String title, int playingtime, boolean gotIt, String comment) {
super();
this.title = title;
this.playingtime = playingtime;
this.gotIt = gotIt;
this.comment = comment;
}
public void print() {
System.out.println(title);
}
}
Object类
单根结构
可以使用Object类型的变量引用任何类型的对象:
Object obi = new Employee(. . .);
阻止继承:final类和方法
不允许扩展的称为final类。假设希望阻止人们定义Executive类的子类,就可以在定义这个类的时候使用final修饰符声明。格式如下:
public final class Excuective extends Managers{
}
类中的特定方法也可以声明为final,这样子类就不能覆盖这个方法。例如:
public class Employee
{
public final String getName()
{
}
}
将方法和类声明为final主要目的是:确保它们不会在子类中改变语义。
强制类型转换
double x = 3.405;
int nx = (int) x;
将表达式x的值转换成整数类型。有时候也需要将某个类的对象引用转换成另外一个类的对象引用。例如:
Manager boss = (Manager) staff[0];
进行类型转换的唯一原因是在暂时忽视对象的实际类型之后,使用对象的全部功能。注意在进行类型转换之前,先查看一下是否能够成功转换,使用instanceof操作符就可以实现。例如:
if (staff[1] instanceof Manager)
{
boss = (Manager) staff[1];
. . .
}
如果这个转换类型不可能成功,编译器就不会进行类型转换。
类型转换要求
hash Code方法
散列码是由对象导出的一个整型值。hashCode方法返回一个整型数值(也可以是负数)。例如Employee类的hashCode方法:
public class Employee
{
public int hashCode
{
return Objects.hash(name,salary,hireDay);
}
}
接口技术主要是用来描述这个类具有什么功能,而并不给出每个功能的具体实现。为了让类实现一个接口,通常需要下面几个步骤:
现在假设希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Comparable接口。
要将类声明为实现某个接口,需要使用关键字implements:
class Employee implements Comparable
当然这里的类需要提供compareTo方法。下面程序给出了对一个Employee类实例数组进行排序的完整代码,用于对一个员工数组排序
package interfaces;
public class Employee implements Comparable<Employee>
{
private String name;
private double salary;
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent/100;
salary += raise;
}
public int compareTo(Employee other) //这里就用了compareTo方法
{
return Double.compare(salary,other.salary);
}
}
package interfaces;
import java.util.Arrays;
public class EmployeeSortTest {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry Hacker",35000);
staff[1] = new Employee("Carl Cracker",75000);
staff[2] = new Employee("Tony Tester",38000);
Arrays.sort(staff);
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
}
}
接口的特性
接口不是类,尤其不能使用new运算符实例化一个接口:
x = new Comparable; //ERROR
然而,尽管不能构造接口的对象,却能声明接口的变量,而且接口的变量必须引用实现了的接口的对象:
Comparable x;
x = new Employee(...) //OK provided Employee implements Comparable
与可以建立类的继承关系一样,接口也可以被扩展。这里允许存在多条从具有较高通用性的接口到较高专用性的接口的链。例如,假设有一个称为Moveable的接口,可以以它为基础扩展一个叫做Powered的接口:
public interface Moveable
{
void move(double x,double y);
}
public interface Powered extends Moveable
{
double milesPerGallon();
double SPEED_LIMIT = 95;
}
//与接口中的方法都自动地被设置为public一样,接口中的域将被自动设置为public static final。
声明类的关键字是class,声明接口的关键字是interface
//interface 接口定义的关键字;接口都需要实现类
public interface UserSerbice {
// public void ss(){ } 报错;接口内不能写方法
//接口中的所有定义其实都是抽象的,默认 public abstract
public abstract void run();
void add(String name);
void delete(String name);
//接口还可以定义变量,所有定义的属性都是静态的常量
public static final int AGE = 99;
int ABC = 99;
}
作用:
public class Application {
public static void main(String[] args) {
xiaduan sxmz = new xiaduan();
sxmz.mingzi("上下没中");
sxmz.nianling(31);
sxmz.shengao(175.8);
sxmz.zhuzhi("内蒙古");
}
}
/*
//抽象类:extende
//类 可以实现接口 implements 接口
//实现了接口的类,就需要重写接口中的方法
public class xiaduan implements jiekou,jiekou2 {
//利用接口实现多继承(jiekou,jiekou2)
//继承类可以方法的实现,但接口只有方法的定义
@Override//jiekou
public void mingzi(String name) {
System.out.println("名字:"+name);
}
@Override//jiekou
public void nianling(int nl) {
System.out.println("岁数:"+nl);
}
@Override//jiekou
public void shengao(double sg) {
System.out.println("身高:"+sg);
}
@Override//jiekou2
public void zhuzhi(String zz) {
System.out.println("住宅:"+zz);
}
}
*/
抽象方法充当着占位的角色,它们的具体实现在子类中。
抽象函数\抽象类
实现抽象函数
继承自抽象类的子类必须覆盖父类中的抽象函数,除非自己本身也是抽象的
两种抽象
程序的业务逻辑与表现无关,表现可以是图形的也可以是文本的,表现可以是当地的也可以是远程的
GUI(图形用户界面)给应用程序提供界面,其中包括窗口、菜单、按钮和其他图形组件,这就是今天大多 数人所熟悉的“典型”应用程序界面。借助GUI来介绍两个设计思想:控制反转和MVC设计模式。布局是指如何在屏幕上放置组件。过去,大多数简单的GUI系统让程序员在二维坐标系上 指定每个组件的x和y坐标(以像素点为单位),这对于现代的GUI系统来说太简单了。因为现代的GUI系统还得考虑不同的屏幕分辨率、不同的字体、用户可改变的窗口尺寸,以及许多其他使得布局困难的因素。所以需要有一种能更通用地指定布局的方法,比如,要求“这个部件应该在那个部件的下面“或者”这个部件在窗口改变尺寸时能自动拉伸,但是其他部件保持尺寸不变”。这些可以通过布局管理器(layout manager)来实现。事件处理是用来响应用户输入的技术。创建了部件并且放在屏幕上合适的位置以后,就得 要有办法来处理诸如用户点击按钮这样的事情。Java类库处理这类事情的模型是基于事件的。 如果用户激活了一个部件(比如,点击按钮或者选择菜单项),系统就会产生一个事件。应用 程序可以收到关于这个事件的通知(以程序的一个方法被调用的方式),然后就可以采取程序该做的动作了。
Swing事件机制
(消息机制)ActionListener
内部类就是指一个类定义在另一个类的内部,从而成为外部类的一个成员。因此一个类中可以有成员变量、方法,还可以有内部类。实际上Java的内部类可以被称为成员类,内部类实际上是它所在类的成员。所以内部类也就具有和成员变量、成员方法相同的性质。比如,成员方法可以访问私有变量,那么成员类也可以访问私有变量了。也就是说,成员类中的成员方法都可以访问成员类所在类的私有变量。内部类最重要的特点就是能够访问外部类的所有成员。
public class Outer {//外部类
private int id = 10;
public void out(){
System.out.println("这是外部类的方法!");
}
public class Inner{//内部类
public void in(){
System.out.println("这是内部类的方法!");
}
}
//内部类可以获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
public static void main(String[] args) {
//外部类通过 new 获取
Outer outer = new Outer();
//内部类通过 外部类 . new 内部类 获得
Outer.Inner inner = outer.new Inner();
}
使用内部类的原因
内部类中声明的所有静态域都必须是final,内部类不能有static方法。
//先实例化外部类,再用外部类实例化内部类
Outer outer = new Outer();//new外部
Outer.Inner inner = outer.new Inner();//new内部
inner.in();
内部类可以获得外部类的私有属性
静态内部类:
不能直接访问非静态的外部类属性(static先于非静态类生成)
局部内部类
在一个方法中可以定义一个局部类,局部类不能用public和private访问说明符进行声明,它的作用域被限定在声明这个局部类的块中。
局部类有两个优势:
public void method(){
class inner{
public void in(){
}
}
}
//不起名直接使用
new Apple().eat();
//new接口
class Test{
public static void main(String[] args) {
new UserService(){
};
}
}
interface UserService{
}
在代码中发现异常时,可将异常放在一个try里面
package field;
import java.util.Scanner;
public class ArrayIndex {
public static void main(String[] args){
int[] a = new int[10];
int index;
Scanner in = new Scanner(System.in);
index = in.nextInt();
a[index] = 10;
System.out.println("hello");
}
}
在这里显示异常
package field;
import java.util.Scanner;
public class ArrayIndex {
public static void main(String[] args){
int[] a = new int[10];
int index;
Scanner in = new Scanner(System.in);
index = in.nextInt();
try {
a[index] = 10;
System.out.println("hello");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("Caught");
}
}
}
将异常放入try里面,即使运行出现异常还是能接着往下运行。
捕捉异常
try{
//可能产生异常的代码
}catch(Type1 id1){
//处理Type1异常的代码
}catch(Type2 id2){
//处理Type2异常的代码
}catch(Type3 id3){
//处理Type3异常的代码
}
可以当出现异常时,捕获它,防止程序停止。
public static void main(String[] args) {
int a = 1;
int b = 0;
//假设要捕获多个异常:从小到大!不然会报错,提示大异常以及覆盖小异常
try { //try 监控区域
System.out.println(a / b);
} catch (Error e) { //catch(想要捕获的异常类型!)捕获异常
System.out.println("Error");
}catch (Exception e){//“e”,代表异常消息
System.out.println("Exception");
}catch (Throwable t){ //最高级,放在最后面
System.out.println("Throwable");
}finally { //处理善后工作,不管报不报异常,都会执行。
System.out.println("finally");
}
//finally 可以不用,但是catch必须有。finally假设Io,资源,关闭工作
//快捷键:选中需要包裹的代码,ctrl+alt+T
/*
try {
System.out.println(a / b);
} catch (Exception e) {
System.exit(0);//程序结束
e.printStackTrace();//打印错误的栈信息
} finally {
}
*/
}
throw
try {
if (b==0){
throw new ArithmeticException();//主动的抛出异常
}
throws
public static void main(String[] args) {
try {
new linshi().test(1,0);
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
}
}
//假设这个方法中,处理不了这个异常。方法上抛出异常throws,由上一级捕获。
public void test(int a,int b)throws ArithmeticException{
if (b == 0) {
throw new ArithmeticException();//throw 主动的抛出异常,一般在方法内
}
System.out.println(a / b);
}
自定义异常
使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况。除此之外用户还可以自定义异常。用户自定义异常类,只需继承
Exception 类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤:
自定义异常类
//自定义异常类
//假设传递数字>10异常
private int tishi;//创建一个提示信息
public Demo01(int a) {//创建一个构造器传递消息
this.tishi = a;
}
//toString打印信息:异常的打印信息
@Override
public String toString() {
return "异常{" + "tishi=" + tishi + '}';
}
throws抛出方法捕获
//创建一个可能会存在异常的方法
static void test(int a) throws Demo01 {
System.out.println("传递的参数为:"+a);
if (a>10){
throw new Demo01(a);
}
System.out.println("ok");
}
public static void main(String[] args) {
try { //赋值并捕获
test(11);
} catch (Demo01 e) {
// if( ){ } 可以增加一些处理异常的代码块
System.out.println("注意:"+e);
}
}
throw方法内捕获
//创建一个可能会存在异常的方法
static void test(int a) {
System.out.println("传递的参数为:"+a);
if (a>10){
try {
throw new Demo01(a);
} catch (Demo01 e) {
System.out.println("注意:"+e);;
}
}
System.out.println("ok");
}
public static void main(String[] args) {
test(15); //赋值
}
实际应用中的经验总结
如果要读文件,需要做以下事情:
异常最大的好处就是清晰的分开了正常的业务逻辑代码和遇到情况时的处理代码。
异常声明
如果你的函数可能抛出异常,就必须在函数头部加以声明
void f() throws TooBig, TooSmall,{
// ...
}
catch怎么匹配异常的
使用catch(Exception e)可以捕捉任何异常
运行时刻异常
异常声明遇到继承关系
流的基础类
InputStream和OutputStream构成了输入输出流的基础类
文件流