JAVA的面向对象(一)

什么是对象:EVERYTHING IS OBJECT(万物皆对象) java

全部的事物都有两个方面:有什么(属性):用来描述对象。程序员

可以作什么(方法):告诉外界对象有那些功能。
后者之前者为基础。
大的对象的属性也能够是一个对象。
 
为何要使用面向对象:
首先,面向对象符合人类看待事物的通常规律。
对象的方法的实现细节是屏蔽的,只有对象方法的实现者了解细节。
方法的定义很是重要。方法有参数,也可能有返回值。
 
注意区分:对象(自己)、对象的实现者、对象的调用者。
分析对象主要从方法开始。
咱们经过类来看待对象,类是对象的抽象。
 
其次,采用面向对象方法可使系统各部分各司其职、各尽所能。
对象之间的耦合性必定要低(好比不一样硬盘和不一样主板之间的关系)。这样才能使每一个对象自己作成最好的。
 
对于对象的要求:高内聚、低耦合,这样容易拼装成为一个系统。
实现高内聚就是要最大限度低提升复用性(复用性好是由于高内聚)。
可复用性是 OOP 的基础。
 
比较面向过程的思想和面向对象的思想:
面向过程的思想:由过程、步骤、函数组成,以过程为核心;
面向对象的思想:以对象为中心,先开发类,获得对象,经过对象之间相互通讯实现功能。
面向过程是先有算法,后有数据结构。
面向对象是先有数据结构,而后再有算法。
 
在用面向对象思想开发的过程当中,能够复用对象就进行复用,如没法进行复用则开发新的对象。
开发过程是用对个简单的对象的多个简单的方法,来实现复杂的功能
从语法上来看,一个类是一个新的数据类型。
在面向对象编程中,除了简单数据类型,就是对象类型。
定义类的格式:
class Student{
  代码
}
注意类名中单词的首字母大写。
实例变量:定义在类中但在任何方法以外。( New 出来的均有初值)
局部变量:定义在方法之中的变量。
局部变量要先赋值,再进行运算,而实例变量均已经赋初值。这是局部变量和实例变量的一大区别。
实例变量的对象赋值为 null
局部变量不容许范围内定义两个同名变量。实例变量的做用域在本类中彻底有效,当被其余的类调用的时候也可能有效。
实例变量和局部变量容许命名冲突。
 
书写方法的格式:
修饰符    返回值         方法名             调用过程当中            方法体
可能出现的例外
 public int/void   addNumber( 参数 )    throw Excepion          {}
 
例:
public int addNumber(int a,int b){
}
注:方法名中的参数 int a,int b 为局部变量
 
类方法中的一类特殊方法:构造方法。
构造方法是当用类生成对象时,系统在生成对象的过程当中利用的方法。
注意:构造方法在生成对象的时候会被调用,但并非构造方法生成了对象。
构造方法没有返回值。格式为: public 方法名。
构造方法的方法名与类名相同。
构造方法是在对象生成的过程当中自动调用,不可能利用指令去调用。
在一个对象的生成周期中构造方法只用一次,一旦这个对象生成,那么这个构造方法失效。
 
用类来生成对象的语句:
Student  s=new Student()
第一个 Student 表示这是用 Student 类进行定义。“ Student() ”表示调用一个无参数的构造方法。
若是 () 中有参数,则系统构造对象的过程当中调用有参的方法。
此时 S 称为一个对象变量。
 Student s 的存储区域存放的是地址:一个对象在硬盘上占有一个连续地址,首地址赋予 s 空间。
S 称为对象 Student 的引用。
注意:在对象变量中存放的是引用(地址);在简单变量中存放的是数值。
 
能够构造多个构造方法,但多个构造方法的参数表必定不一样,参数顺序不一样即属于不一样的构造方法:
public student(string name,int a){
}
public student(int a,string name){
}
为两个不一样的构造方法。
若是咱们未给系统提供一个构造方法,那么系统会自动提供一个为空的构造方法。
练习:写一个类,定义一个对象,定义两个构造方法:一个有参,一个无参。
(编写一个程序验证对象的传递的值为地址)
注意下面这种形式:
static void changename(student stu){stu.setName “LUCY”}
注意生成新的对象与旧对象指向无关,生成新对象生命消亡与旧对象无关。
 
面向对象方法的重载( overloading )和覆盖( overriding )。
在有些 JAVA 书籍中将 overriding 称为重载, overloading 称为过载。
Overloading 在一个类中能够定义多个同名方法,各个方法的参数表必定不一样。但修饰词可能相同,返回值也可能相同。
在程序的编译过程当中根据变量类型来找相应的方法。所以也有人认为 overloading 是编译时的多态,之后咱们还会学到运行时多态。
 
为何会存在 overloading 技术呢?做为应对方法的细节。
利用类型的差别来影响对方法的调用。
吃()能够分为吃肉,吃菜,吃药,在一个类中能够定义多个吃方法。
 
构造方法也能够实现 overloading 。例:
public void teach(){};
public void teach(int a){};
public void teach(String a){} 为三种不一样的方法。
 
Overloading 方法是从低向高转。
Byte short float int long double
 
在构造方法中, this 表示本类的其余构造方法:
student(){};
student(string n){
 this();// 表示调用 student()
}
若是调用 student(int a) 则为 this(int a)
特别注意 :用 this 调用其余构造方法时, this 必须为第一条语句,而后才是其余语句。
 
This 表示当前对象。
 
Public void printNum(){
 Int number=40
 System.out.println(this.number);
}
此时打印的是实例变量,而非局部变量,即定义在类中而非方法中的变量。
 
This.number 表示实例变量。
谁调用 this.number 那么谁即为当前 (this) 对象的 number 方法。
 
封装:使对象的属性尽量私有,对象的方法尽量的公开。用 private 表示此成员属性为该类的私有属性。
 
Public 表示该属性(方法)公开;
Private 表示该属性(方法)为只有本类内部能够访问(类内部可见)。
(想用 private 还要用 set get 方法供其余方法调用,这样能够保证对属性的访问方式统一,而且便于维护访问权限以及属性数据合法性)
若是没有特殊状况,属性必定私有,方法该公开的公开。
若是不指明谁调用方法,则默认为 this
区分实例变量和局部变量时必定要写 this
11.29
继承:
父类( SuperClass )和 子类( SonClass )。
父类的非私有化属性和方法能够默认继承到子类。
Class Son extends Father{
}
而若是父类中的私有方法被子类调用的话,则编译报错。
 
父类的构造方法子类不能够继承,更不存在覆盖的问题。(非构造方法能够)
若是子类访问父类的构造方法,则在编译的时候提示访问不到该方法。
JAVA 中不容许多继承,一个类有且只有一个父类(单继承)。
JAVA 的数据结构为树型结构,而非网状。( JAVA 经过接口和内部类实现多继承)
 
方法的覆盖( overriding
方法的重载并不必定是在一个类中:子类能够从父类继承一个方法,也能够定义一个同名异参的方法,也称为 overloading
当子类从父类继承一个无参方法,而又定义了一个一样的无参方法,则子类新写的方法覆盖父类的方法,称为覆盖。(注意返回值类型也必须相同,不然编译出错。)
若是方法不一样,则成重载。
 
对于方法的修饰词,子类方法要比父类的方法范围更加的宽泛。
父类为 public ,那么子类为 private 则出现错误。
之因此构造方法先运行父类再运行子类是由于构造方法是没法覆盖的。
如下范围依次由严到宽:
private :本类访问;
default :表示默认,不只本类访问,并且是同包可见。
Protected :同包可见 + 不一样包的子类可见
Public :表示全部的地方都可见。
 
当构造一个对象的时候,系统先构造父类对象,再构造子类对象。
构造一个对象的顺序:(注意:构造父类对象的时候也是这几步)
    递归地构造父类对象;
    顺序地调用本类成员属性赋初值语句;
    本类的构造方法。
 
Super() 表示调用父类的构造方法。
Super() 也和 this 同样必须放在第一行。
This() 用于调用本类的构造方法。
若是没有定义构造方法,那么就会调用父类的无参构造方法,即 super()
 
要养成良好的编程习惯:就是要加上默认的父类无参的构造方法。
思考:但是若是咱们没有定义无参的构造方法,而在程序中构造了有参的构造方法,那么若是方法中没有参数,那么系统还会调用有参的构造方法么?应该不会。
 
多态:多态指的是编译时类型变化,而运行时类型不变。
多态分两种:
    编译时多态:编译时动态重载;
    运行时多态:指一个对象能够具备多个类型。
 
对象是客观的,人对对象的认识是主观的。
例:
Animal a=new Dog() ;查看格式名称;
Dog d=(Dog)a 。声明父类来引用子类。
(思考上面的格式)
 
运行时多态的三原则:(应用时为覆盖)
一、           对象不变;(改变的是主观认识)
二、            对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型必定要为运行时类型的父类(或者同类型)。
对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就能够调用运行时类型。注意:a和d指向同一对象。
三、            在程序的运行时,动态类型断定。运行时调用运行时类型,即它调用覆盖后的方法。
 
关系运算符: instanceof
a instanceof Animal;( 这个式子的结果是一个布尔表达式 )
a 为对象变量, Animal 是类名。
上面语句是断定 a 是否能够贴 Animal 标签。若是能够贴则返回 true ,不然返回 false
在上面的题目中: a instanceof Animal 返回  True
                 a instanceof Dog 也返回  True
instanceof 用于断定是否将前面的对象变量赋值后边的类名。
Instanceof 通常用于在强制类型转换以前断定变量是否能够强制转换。
 
若是 Animal a=new Animal()
Dog d=Dog()a;
此时编译无误,但运行则会报错。
 
Animal a=new Dog() 至关于下面语句的功能:
Animal a=getAnimal()
Public static Animal.getAnimal;
Return new Dog()
 
封装、继承、多态为面向对象的三大基石(特性)。
 
运行时的动态类型断定针对的是方法。运行程序访问的属性仍为编译时属性。
 
Overloading 针对的是编译时类型,不存在运行时的多态。
 
习题:创建一个 shape 类,有 circle rect 子类。
Shape 类有 zhouchang() area() 两种方法。
(正方形) squ rect 子类, rect cha() 用于比较长宽的差。
 
覆盖时考虑子类的 private 及父类的 public (考虑多态),之因此这样是避免调用 A 时出现实际调用 B 的状况。而出现错误。
11.29 下午讲的是教程上的 Module6
Module6-7 包括:面向对象高级、内部类、集合、反射(暂时不讲)、例外。
面向对象高级、集合和例外都是面向对象的核心内容。
 
 
面向对象高级:    修饰符:
static: 可修饰变量(属性); ②可修饰方法;③可修饰代码块。
Static int data 语句说明 data 为类变量,为一个类的共享变量,属于整个类。
Int data 为实例变量。
例:
static int data;
m1.data=0;
m1.data++ 的结果为 1, 此时 m2.data 的结果也为 1
Static 定义的是一块为整个类共有的一块存储区域,其发生变化时访问到的数据都时通过变化的。
其变量能够经过类名去访问:类名 . 变量名。与经过访问对象的编译时类型访问类变量为等价的。
 
Public static void printData(){}
代表此类方法为类方法(静态方法)
静态方法不须要有对象,可使用类名调用。
静态方法中不容许访问类的非静态成员,包括成员的变量和方法,由于此时是经过类调用的,没有对象的概念。 This.data 是不可用的。
 
通常状况下,主方法是静态方法,因此可调用静态方法,主方法为静态方法是由于它是整个软件系统的入口,而进入入口时系统中没有任何对象,只能使用类调用。
 
覆盖不适用于静态方法。
静态方法不可被覆盖。(容许在子类中定义同名静态方法,可是没有多态,严格的讲,方法间没有多态就不能称为覆盖)
static 修饰代码块时(注:此代码块要在此类的任何一个方法以外),那么这个代码块在代码被装载进虚拟机生成对象的时候可被装载一次,之后不再执行了。
通常静态代码块被用来初始化静态成员。
 
Static 一般用于 Singleton 模式开发:
Singleton 是一种设计模式,高于语法,能够保证一个类在整个系统中仅有一个对象。
 
11.30
 
final 能够修饰类、属性、方法。
 
当用 final 修饰类的时候,此类不可被继承,即 final 类没有子类。这样能够用 final 保证用户调用时动做的一致性,能够防止子类覆盖状况的发生。
 
当利用 final 修饰一个属性(变量)的时候,此时的属性成为常量。
JAVA 利用 final 定义常量(注意在 JAVA 命名规范中常量须要所有字母都大写):
Final int AGE=10
常量的地址不可改变,但在地址中保存的值(即对象的属性)是能够改变的。
 
Final 能够配合 static 使用。  
Static final int age=10
 
JAVA 中利用 public static final 的组合方式对常量进行标识(固定格式)。
 
对于在构造方法中利用 final 进行赋值的时候,此时在构造以前系统设置的默认值相对于构造方法失效。
 
 
常量(这里的常量指的是实例常量:即成员变量)赋值:
①在初始化的时候经过显式声明赋值。Final int x=3;
②在构造的时候赋值。
局部变量能够随时赋值。
 
利用final定义方法:这样的方法为一个不可覆盖的方法。
Public final void print(){}
为了保证方法的一致性(即不被改变),可将方法用final定义。
 
若是在父类中有final定义的方法,那么在子类中继承同一个方法。
 
若是一个方法前有修饰词private或static,则系统会自动在前面加上final。即private和static方法默认均为final方法。
 
注:final并不涉及继承,继承取决于类的修饰符是否为private、default、protected仍是public。也就是说,是否继承取决于这个方法对于子类是否可见。
Abstract( 抽象)能够修饰类、方法
若是将一个类设置为abstract,则此类必须被继承使用。此类不可生成对象,必须被继承使用。
Abstract 能够将子类的共性最大限度的抽取出来,放在父类中,以提升程序的简洁性。
Abstract 虽然不能生成对象,可是能够声明,做为编译时类型,但不能做为运行时类型。
Final abstract永远不会同时出现。
 
abstract用于修饰方法时,此时该方法为抽象方法,此时方法不须要实现,实现留给子类覆盖,子类覆盖该方法以后方法才可以生效。
 
注意比较:
private void print(){} ;此语句表示方法的空实现。
Abstract void print() ; 此语句表示方法的抽象,无实现。
 
若是一个类中有一个抽象方法,那么这个类必定为一个抽象类。
反之,若是一个类为抽象类,那么其中可能有非抽象的方法。
 
若是让一个非抽象类继承一个含抽象方法的抽象类,则编译时会发生错误。由于当一个非抽象类继承一个抽象方法的时候,本着只有一个类中有一个抽象方法,那么这个类必须为抽象类的原则。这个类必须为抽象类,这与此类为非抽象冲突,因此报错。
 
因此子类的方法必须覆盖父类的抽象方法。方法才可以起做用。
只有将理论被熟练运用在实际的程序设计的过程当中以后,才能说理论被彻底掌握!
为了实现多态,那么父类必须有定义。而父类并不实现,留给子类去实现。此时可将父类定义成abstract类。若是没有定义抽象的父类,那么编译会出现错误。
 
Abstract static 不能放在一块儿,不然便会出现错误。(这是由于 static 不可被覆盖,而 abstract 为了生效必须被覆盖。)
 
例:(本例已存在 \CODING\abstract\TestClass.java 文件中)
public class TestClass{
 public static void main(String[] args){
SuperClass sc=new SubClass();
Sc.print();
}
Abstract class SuperClass{
Abstract void print();}
}
class SubClass extends SuperClass(){
 void print(){
System.out.println(“print”);}
}
 
JAVA 的核心概念:接口( interface
接口与类属于同一层次,实际上,接口是一种特殊的抽象类。
:
 interface IA{
}
public interface :公开接口
与类类似,一个文件只能有一个 public 接口,且与文件名相同。
在一个文件中不可同时定义一个 public 接口和一个 public 类。
 
一个接口中,全部方法为公开、抽象方法;全部的属性都是公开、静态、常量。
 
一个类实现一个接口的格式:
class IAImple implements IA{
};
 
一个类实现接口,至关于它继承一个抽象类。
 
类必须实现接口中的方法,不然其为一抽象类。
实现中接口和类相同。
 
接口中可不写 public ,但在子类中实现接口的过程当中 public 不可省。
(若是剩去 public 则在编译的时候提示出错:对象没法从接口中实现方法。)
 
注:
    一个类除继承另一个类,还能够实现接口;
class IAImpl extends java.util.Arrylist implement IA{}
                 继承类                    实现接口
这样能够实现变相的多继承。
    一个类只能继承另一个类,可是它能够继承多个接口,中间用“,”隔开。
Implements IA,IB
所谓实现一个接口,就是指实现接口中的方法。
    接口和接口之间能够定义继承关系,而且接口之间容许实现多继承。
例:interface IC extends IA,IB{};
接口也能够用于定义对象
IA I=new IAImpl();
实现的类从父类和接口继承的均可作运行时类型。
IAImple extends A implement IA,IB
IB I=new IAImple();
I instance of IAImple;
I instance of A;
I instance of IA;
I instance of IB;
返回的结果均为true.
 
接口和多态都为JAVA技术的核心。
 
接口每每被咱们定义成一类XX的东西。
接口其实是定义一个规范、标准。
 
    经过接口能够实现不一样层次、不一样体系对象的共同属性;
经过接口实现write once as anywhere.
JAVA数据库链接为例子:JDBC制定标准;数据厂商实现标准;用户使用标准。
接口一般用来屏蔽底层的差别。
②接口也由于上述缘由被用来保持架构的稳定性。
 
JAVA 中有一个特殊的类: Object 。它是 JAVA 体系中全部类的父类(直接父类或者间接父类)。
 
此类中的方法可使所的类均继承。
 
如下介绍的三种方法属于 Object:
(1)   finalize 方法:当一个对象被垃圾回收的时候调用的方法。
(2)   toString(): 是利用字符串来表示对象。
当咱们直接打印定义的对象的时候,隐含的是打印 toString() 的返回值。
能够经过子类做为一个 toString() 来覆盖父类的 toString()
以取得咱们想获得的表现形式,即当咱们想利用一个自定义的方式描述对象的时候,咱们应该覆盖 toString()
(3)equal
首先试比较下例:
String A=new String(“hello”);
String A=new String(“hello”);
A==B( 此时程序返回为 FALSE)
由于此时 AB 中存的是地址,由于建立了新的对象,因此存放的是不一样的地址。
 
附加知识:
字符串类为 JAVA 中的特殊类, String 中为 final 类,一个字符串的值不可重复。所以在 JAVA VM (虚拟机)中有一个字符串池,专门用来存储字符串。若是遇到 String a=”hello” 时(注意没有 NEW ,不是建立新串),系统在字符串池中寻找是否有 ”hello” ,此时字符串池中没有 ”hello” ,那么系统将此字符串存到字符串池中,而后将 ”hello” 在字符串池中的地址返回 a 。若是系统再遇到 String b=”hello” ,此时系统能够在字符串池中找到  “hello” 。则会把地址返回 b ,此时 a b 为相同。
 
 
String a=”hello”;
System.out.println(a==”hello”);
系统的返回值为 true
 
故若是要比较两个字符串是否相同(而不是他们的地址是否相同)。能够对 a 调用 equal:
System.out.println(a.equal(b));
equal 用来比较两个对象中字符串的顺序。
a.equal(b) a b 的值的比较。
 
 
注意下面程序:
student a=new student(“LUCY”,20);
student b=new student(“LUCY”,20);
System.out.println(a==b);
System.out.println(a.equal(b));
此时返回的结果均为 false
 
如下为定义 equal (加上这个定义,返回 ture false
public boolean equals(Object o){
 student s=(student)o;
 if (s.name.equals(this.name)&&s.age==this.age)
else return false;
} 若是 equals() 返回的值为
 
如下为实现标准 equals 的流程:
public boolean equals(Object o){
 if (this==o) return trun; // 此时二者相同
 if (o==null) return false;
 if (! o instanceof strudent) return false; // 不一样类
 studeng s=(student)o; // 强制转换
  if (s.name.equals(this.name)&&s.age==this.age) return true;
else return false;
}
 
以上过程为实现 equals 的标准过程。
 
  练习:创建一个 employee 类,有 String name,int id,double salary. 运用 get set 方法,使用 toString ,使用 equals
 
封装类:
JAVA 为每个简单数据类型提供了一个封装类,使每一个简单数据类型能够被 Object 来装载。
除了 int char ,其他类型首字母大写即成封装类。
转换字符的方式:
int I=10;
String s=I+” ”;
String s1=String.valueOf(i);
 
Int I=10;
Interger I_class=new integer(I);
 
javadoc 的帮助文档。
附加内容:
== ”在任什么时候候都是比较地址,这种比较永远不会被覆盖。
 
程序员本身编写的类和 JDK 类是一种合做关系。(由于多态的存在,可能存在咱们调用 JDK 类的状况,也可能存在 JDK 自动调用咱们的类的状况。)
注意:类型转换中 double\interger\string 之间的转换最多。
12.01
内部类:
(注:全部使用内部类的地方均可以不用内部类,使用内部类可使程序更加的简洁,便于命名规范和划分层次结构)。
内部类是指在一个外部类的内部再定义一个类。
内部类做为外部类的一个成员,而且依附于外部类而存在的。
内部类可为静态,可用 PROTECTED PRIVATE 修饰。(而外部类不能够:外部类只能使用 PUBLIC DEFAULT )。
 
内部类的分类:
成员内部类、
局部内部类、
静态内部类、
匿名内部类(图形是要用到,必须掌握)。
 
    成员内部类:做为外部类的一个成员存在,与外部类的属性、方法并列。
内部类和外部类的实例变量能够共存。
在内部类中访问实例变量: this. 属性
在内部类访问外部类的实例变量:外部类名 .this. 属性。
 
成员内部类的优势:
内部类做为外部类的成员,能够访问外部类的私有成员或属性。(即便将外部类声明为 PRIVATE ,可是对于处于其内部的内部类仍是可见的。)
用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的 private 还要小的访问权限。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为彻底不一样的两类。
对于一个名为 outer 的外部类和其内部定义的名为 inner 的内部类。编译完成后出现 outer.class outer$inner.class 两类。
 
(编写一个程序检验:在一个 TestOuter.java 程序中验证内部类在编译完成以后,会出现几个 class.
 
成员内部类不能够有静态属性。(为何?)
 
若是在外部类的外部访问内部类,使用 out.inner.
 
创建内部类对象时应注意:
在外部类的内部能够直接使用 inner s=new inner(); (由于外部类知道 inner 是哪一个类,因此能够生成对象。)
而在外部类的外部,要生成( new )一个内部类对象,须要首先创建一个外部类对象(外部类可用),而后在生成一个内部类对象。
Outer.Inner in=Outer.new.Inner()
错误的定义方式:
Outer.Inner in=new Outer.Inner()
注意:当 Outer 是一个 private 类时,外部类对于其外部访问是私有的,因此就没法创建外部类对象,进而也没法创建内部类对象。
 
    局部内部类:在方法中定义的内部类称为局部内部类。
与局部变量相似,在局部内部类前不加修饰符 public private ,其范围为定义它的代码块。
 
注意:局部内部类不只能够访问外部类实例变量,还能够访问外部类的局部变量(但此时要求外部类的局部变量必须为 final ??
在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。
要想使用局部内部类时须要生成对象,对象调用方法,在方法中才能调用其局部内部类。
 
    静态内部类:(注意:前三种内部类与变量相似,因此能够对照参考变量)
静态内部类定义在类中,任何方法外,用 static 定义。
静态内部类只能访问外部类的静态成员。
生成( new )一个静态内部类不须要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象能够直接生成:
Outer.Inner in=new Outer.Inner()
而不须要经过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。
静态内部类不可用 private 来进行定义。例子:
对于两个类,拥有相同的方法:
People
{
 run();
}
Machine{
   run();
}
此时有一个 robot 类:
class Robot extends People implement Machine.
此时 run() 不可直接实现。
注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。
用接口不能彻底地实现多继承,用接口配合内部类才能实现真正的多继承。
 
    匿名内部类(必须掌握):
匿名内部类是一种特殊的局部内部类,它是经过匿名类实现接口。
IA 被定义为接口。
IA I=new IA(){};
注:一个匿名内部类必定是在 new 的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,咱们使用其父类名。
因其为局部内部类,那么局部内部类的全部限制都对其生效。
匿名内部类是惟一一种无构造方法类。
匿名内部类在编译的时候由系统自动起名 Out$1.class
 
若是一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。
因匿名内部类无构造方法,因此其使用范围很是的有限。
(下午:) Exception (例外 / 异常)(教程上的 MODEL7
对于程序可能出现的错误应该作出预案。
例外是程序中全部出乎意料的结果。(关系到系统的健壮性)
 
JAVA 会将全部的错误封装成为一个对象,其根本父类为 Throwable
Throwable 有两个子类: Error Exception
一个 Error 对象表示一个程序错误,指的是底层的、低级的、不可恢复的严重错误。此时程序必定会退出,由于已经失去了运行所必须的物理环境。
对于 Error 错误咱们没法进行处理,由于咱们是经过程序来应对错误,但是程序已经退出了。
咱们能够处理的 Throwable 对象中只有 Exception 对象(例外 / 异常)。
Exception 有两个子类: Runtime exception (未检查异常)
Runtime exception (已检查异常)
(注意:不管是未检查异常仍是已检查异常在编译的时候都不会被发现,在编译的过程当中检查的是程序的语法错误,而异常是一个运行时程序出错的概念。)
Exception 中,全部的非未检查异常都是已检查异常,没有另外的异常!!
 
未检查异常是由于程序员没有进行必要的检查,由于他的疏忽和错误而引发的异常。必定是属于虚拟机内部的异常(好比空指针)。
 
应对未检查异常就是养成良好的检查习惯。
已检查异常是不可避免的,对于已检查异常必须实现定义好应对的方法。
已检查异常确定跨越出了虚拟机的范围。(好比“未找到文件”)
 
如何处理已检查异常(对于全部的已检查异常都要进行处理):
首先了解异常造成的机制:
当一个方法中有一条语句出现了异常,它就会 throw (抛出)一个例外对象,而后后面的语句不会执行返回上一级方法,其上一级方法接受到了例外对象以后,有可能对这个异常进行处理,也可能将这个异常转到它的上一级。
对于接收到的已检查异常有两种处理方式: throws try 方法。
 
注意:出错的方法有多是 JDK ,也多是程序员写的程序,不管谁写的,抛出必定用 throw
 
例: public void print() throws Exception.
 
对于方法 a ,若是它定义了 throws Exception 。那么当它调用的方法 b 返回异常对象时,方法 a 并不处理,而将这个异常对象向上一级返回,若是全部的方法均不进行处理,返回到主方法,程序停止。(要避免全部的方法都返回的使用方法,由于这样出现一个很小的异常就会令程序停止)。
 
若是在方法的程序中有一行 throw new Exception() ,返回错误,那么其后的程序不执行。由于错误返回后,后面的程序确定没有机会执行,那么 JAVA 认为之后的程序没有存在的必要。
 
对于 try …… catch 格式:
try  { 可能出现错误的代码块 }   catch(exception e){ 进行处理的代码 }
                                 对象变量的声明
 
用这种方法,若是代码正确,那么程序不通过 catch 语句直接向下运行;
若是代码不正确,则将返回的异常对象和 e 进行匹配,若是匹配成功,则处理其后面的异常处理代码。(若是用 exception 来声明 e 的话,由于 exception 为全部 exception 对象的父类,全部确定匹配成功)。处理完代码后这个例外就彻底处理完毕,程序会接着从出现异常的地方向下执行(是从出现异常的地方仍是在 catch 后面呢?利用程序进行验证)。最后程序正常退出。
 
Try 中若是发现错误,即跳出 try 去匹配 catch ,那么 try 后面的语句就不会被执行。
一个 try 能够跟进多个 catch 语句,用于处理不一样状况。当一个 try 只能匹配一个 catch
咱们能够写多个 catch 语句,可是不能将父类型的 exception 的位置写在子类型的 excepiton 以前,由于这样父类型确定先于子类型被匹配,全部子类型就成为废话。 JAVA 编译出错。
 
try catch 后还能够再跟一子句 finally 。其中的代码语句不管如何都会被执行(由于 finally 子句的这个特性,因此通常将释放资源,关闭链接的语句写在里面)。
 
若是在程序中书写了检查(抛出) exception 可是没有对这个可能出现的检查结果进行处理,那么程序就会报错。
而若是只有处理状况( try )而没有相应的 catch 子句,则编译仍是通不过。
如何知道在编写的程序中会出现例外呢
1.  调用方法,查看 API 中查看方法中是否有已检查错误。
2.  在编译的过程当中看提示信息,而后加上相应的处理。
 
Exception 有一个 message 属性。在使用 catch 的时候能够调用:
Catch(IOException e){System.out.println(e.message())};
Catch(IOException e){e.printStackTrace()};
上面这条语句回告诉咱们出错类型所历经的过程,在调试的中很是有用。
 
开发中的两个道理:
①如何控制try的范围:根据操做的连动性和相关性,若是前面的程序代码块抛出的错误影响了后面程序代码的运行,那么这个咱们就说这两个程序代码存在关联,应该放在同一个try中。
    对已经查出来的例外,有throw(积极)和try catch(消极)两种处理方法。
对于try catch放在可以很好地处理例外的位置(即放在具有对例外进行处理的能力的位置)。若是没有处理能力就继续上抛。
 
当咱们本身定义一个例外类的时候必须使其继承excepiton或者RuntimeException。
Throw 是一个语句,用来作抛出例外的功能。
throws是表示若是下级方法中若是有例外抛出,那么本方法不作处理,继续向上抛出。
Throws 后跟的是例外类型。
断言是一种调试工具(assert)
其后跟的是布尔类型的表达式,若是表达式结果为真不影响程序运行。若是为假系统出现低级错误,在屏幕上出现assert信息。
Assert 只是用于调试。在产品编译完成后上线assert代码就被删除了。
 
方法的覆盖中,若是子类的方法抛出的例外是父类方法抛出的例外的父类型,那么编译就会出错:子类没法覆盖父类。
结论:子类方法不可比父类方法抛出更多的例外。子类抛出的例外或者与父类抛出的例外一致,或者是父类抛出例外的子类型。或者子类型不抛出例外。
若是父类型无 throws 时,子类型也不容许出现 throws 。此时只能使用 try catch
 
练习:写一个方法: int add(int a,int b)
{
 return a+b
}
a+b=100; 抛出 100 为异常处理。
12.02
集合(从本部分开始涉及 API
集合是指一个对象容纳了多个对象,这个集合对象主要用来管理维护一系列类似的对象。
数组就是一种对象。(练习:如何编写一个数组程序,并进行遍历。)
java.util.* 定义了一系列的接口和类,告诉咱们用什么类 NEW 出一个对象,能够进行超越数组的操做。
(注: JAVA1.5 JAVA1.4 的最大改进就是增长了对范型的支持)
集合框架接口的分类:(分 collection 接口 map 接口)
            Collection 接口                         Map 接口
 
 


 

List 接口          Set 接口                         SortedMap 接口
 
 


 

                    SortedSet 接口
JAVA 中全部与集合有关的实现类都是这六个接口的实现类。
 
Collection 接口:集合中每个元素为一个对象,这个接口将这些对象组织在一块儿,造成一维结构。
 
List 接口表明按照元素必定的相关顺序来组织(在这个序列中顺序是主要的), List 接口中数据可重复。
 
Set 接口是数学中集合的概念:其元素无序,且不可重复。(正好与 List 对应)
 
SortedSet 会按照数字将元素排列,为“可排序集合”。
 
Map 接口中每个元素不是一个对象,而是一个键对象和值对象组成的键值对( Key-Value )。
Key-Value 是用一个不可重复的 key 集合对应可重复的 value 集合。(典型的例子是字典:经过页码的 key 值找字的 value 值)。
例子:
key1 value1;
key2 value2;
key3 value3.
SortedMap :若是一个 Map 能够根据 key 值排序,则称其为 SortedMap 。(如字典)
!! 注意数组和集合的区别:数组中只能存简单数据类型。 Collection 接口和 Map 接口只能存对象。
 
如下介绍接口:
List 接口:(介绍其下的两个实现类: ArrayList LinkedList
ArrayList 和数组很是相似,其底层 也用数组组织数据, ArrayList 是动态可变数组。
    底层:指存储格式。说明 ArrayList 对象都是存在于数组中。
注:数组和集合都是从下标 0 开始。
ArrayList 有一个 add(Object o) 方法用于插入数组。
ArrayList 的使用:(完成这个程序)
import java.util.*
ArrayList 在一个数组中添加数据,并遍历。
ArrayList 中数组的顺序与添加顺序一致。
只有 List 可用 get size 。而 Set 则不可用(因其无序)。
Collection 接口都是经过 Iterator() (即迭代器)来对 Set List 遍历。
经过语句: Iterator it=c.iterator(); 获得一个迭代器,将集合中全部元素顺序排列。而后能够经过 interator 方法进行遍历,迭代器有一个游标(指针)指向首位置。
Interator hasNext() ,用于判断元素右边是否还有数据,返回 True 说明有。而后就能够调用 next 动做。 Next() 会将游标移到下一个元素,并把它所跨过的元素返回。(这样就能够对元素进行遍历)
练习:写一个程序,输入对象信息,比较基本信息。
集合中每个元素都有对象,若有字符串要通过强制类型转换。
Collections 是工具类,全部方法均为有用方法,且方法为 static
Sort 方法用于给 List 排序。
Collections.Sort() 分为两部分,一部分为排序规则;一部分为排序算法。
规则用来判断对象;算法是考虑如何排序。
对于自定义对象, Sort 不知道规则,因此没法比较。这种状况下必定要定义排序规则。方式有两种:
    java.lang 下面有一个接口:Comparable(可比较的)
可让自定义对象实现一个接口,这个接口只有一个方法comparableTo(Object o)
其规则是当前对象与o对象进行比较,其返回一个int值,系统根据此值来进行排序。
如 当前对象>o对象,则返回值>0;(可将返回值定义为1)
如 当前对象=o对象,则返回值=0;
如 当前对象<o对象,则返回值〈0。(可将返回值定义为-1)
TestArraylist的java代码。
咱们经过返回值1和-1位置的调换来实现升序和降序排列的转换。
 
    java.util 下有一个Comparator(比较器)
它拥有compare(),用来比较两个方法。
要生成比较器,则用Sort中Sort(List,List(Compate))
第二种方法更灵活,且在运行的时候不用编译。
 
注意:要想实现comparTo()就必须在主方法中写上implement comparable.
 
练习:生成一个EMPLOYEE类,而后将一系列对象放入到ArrayList。用Iterator遍历,排序以后,再进行遍历。
 
集合的最大缺点是没法进行类型断定(这个缺点在 JAVA1.5 中已经解决),这样就可能出现由于类型不一样而出现类型错误。
解决的方法是添加类型的判断。    
 
LinkedList 接口(在代码的使用过程当中和 ArrayList 没有什么区别)
ArrayList 底层是 object 数组,因此 ArrayList 具备数组的查询速度快的优势以及增删速度慢的缺点。
而在 LinkedList 的底层是一种双向循环链表。在此链表上每个数据节点都由三部分组成:前指针(指向前面的节点的位置),数据,后指针(指向后面的节点的位置)。最后一个节点的后指针指向第一个节点的前指针,造成一个循环。
双向循环链表的查询效率低可是增删效率高。因此 LinkedList 具备查询效率低但增删效率高的特色。
ArrayList LinkedList 在用法上没有区别,可是在功能上仍是有区别的。
LinkedList 常常用在增删操做较多而查询操做不多的状况下:队列和堆栈。
队列:先进先出的数据结构。
堆栈:后进先出的数据结构。
注意:使用堆栈的时候必定不能提供方法让不是最后一个元素的元素得到出栈的机会。
LinkedList 提供如下方法:( ArrayList 无此类方法)
addFirst();   
removeFirst();
 addLast();
 removeLast();
在堆栈中, push 为入栈操做, pop 为出栈操做。
 
Push addFirst() pop removeFirst() ,实现后进先出。
isEmpty()-- 其父类的方法,来判断栈是否为空。
 
在队列中, put 为入队列操做, get 为出队列操做。
Put addFirst() get removeLast() 实现队列。
 
List 接口的实现类( Vector )(与 ArrayList 类似,区别是 Vector 是重量级的组件,使用使消耗的资源比较多。)
结论:在考虑并发的状况下用 Vector (保证线程的安全)。
在不考虑并发的状况下用 ArrayList (不能保证线程的安全)。
 
面试经验(知识点):
java.util.stack stack 即为堆栈)的父类为 Vector 。但是 stack 的父类是最不该该为 Vector 的。由于 Vector 的底层是数组,且 Vector get 方法(意味着它可能访问到并不属于最后一个位置元素的其余元素,很不安全)。
对于堆栈和队列只能用 push 类和 get 类。
Stack 类之后不要轻易使用。
!!!实现堆栈必定要用 LinkedList
(在 JAVA1.5 中, collection queue 来实现队列。)
 
Set-HashSet 实现类:
遍历一个 Set 的方法只有一个:迭代器( interator )。
HashSet 中元素是无序的(这个无序指的是数据的添加顺序和后来的排列顺序不一样),并且元素不可重复。
Object 中除了有 final() toString() equals() ,还有 hashCode()
HashSet 底层用的也是数组。
当向数组中利用 add(Object o) 添加对象的时候,系统先找对象的 hashCode
int hc=o.hashCode(); 返回的 hashCode 为整数值。
Int I=hc%n; n 为数组的长度),取得余数后,利用余数向数组中相应的位置添加数据,以 n 6 为例,若是 I=0 则放在数组 a[0] 位置,若是 I=1, 则放在数组 a[1] 位置。若是 equals() 返回的值为 true ,则说明数据重复。若是 equals() 返回的值为 false ,则再找其余的位置进行比较。这样的机制就致使两个相同的对象有可能重复地添加到数组中,由于他们的 hashCode 不一样。
若是咱们可以使两个相同的对象具备相同 hashcode ,才能在 equals() 返回为真。
在实例中,定义 student 对象时覆盖它的 hashcode
由于 String 类是自动覆盖的,因此当比较 String 类的对象的时候,就不会出现有两个相同的 string 对象的状况。
如今,在大部分的 JDK 中,都已经要求覆盖了 hashCode
结论:如将自定义类用 hashSet 来添加对象,必定要覆盖 hashcode() equals() ,覆盖的原则是保证当两个对象 hashcode 返回相同的整数,并且 equals() 返回值为 True
若是偷懒,没有设定 equals() ,就会形成返回 hashCode 虽然结果相同,但在程序执行的过程当中会屡次地调用 equals() ,从而影响程序执行的效率。
 
咱们要保证相同对象的返回的 hashCode 必定相同,也要保证不相同的对象的 hashCode 尽量不一样(由于数组的边界性, hashCode 仍是可能相同的)。例子:
public int hashCode(){
 return name.hashcode()+age;
}
这个例子保证了相同姓名和年龄的记录返回的 hashCode 是相同的。
 
使用 hashSet 的优势:
hashSet 的底层是数组,其查询效率很是高。并且在增长和删除的时候因为运用的 hashCode 的比较开肯定添加元素的位置,因此不存在元素的偏移,因此效率也很是高。由于 hashSet 查询和删除和增长元素的效率都很是高。
可是 hashSet 增删的高效率是经过花费大量的空间换来的:由于空间越大,取余数相同的状况就越小。 HashSet 这种算法会创建许多无用的空间。
使用 hashSet 接口时要注意,若是发生冲突,就会出现遍历整个数组的状况,这样就使得效率很是的低。
 
练习: new 一个 hashset ,插入 employee 对象,不容许重复,而且遍历出来。
 
添加知识点:
集合对象存放的是一系列对象的引用。
例:
Student S
Al.add(s);
s.setName(“lucy”);
Student s2=(Student)(al.get(o1));
可知 s2 也是 s
相关文章
相关标签/搜索