继承和多态这一章的知识点确实很多,篇幅多多少少有点长,希望你可以认真读完*~*
目录
3.设计一个小程序(GeometricObject、Circle、Rectangle)
Java中的所有类都继承自java.lang.Object类。
4.使用java.util.Collections类中的静态方法sort来对元素进行排序
5.使用java.util.Collections类中的静态方法max和min分别返回列表中元素的最大元素和最小元素
6.使用java.util.Collections类中的静态方法shuffle随机打乱列表元素
第一部分:父类和子类
1.继承:
面向对象编程支持从已经存在的类中定义一个新的类,称为继承。
2.父类和子类
继承使得你可以定义一个通用的类(也就是父类),之后继承该类为一个更特殊的类(也就是子类)。
在java中,如果类c1继承另一个类c2,则c1称为子类,c2称为父类;
父类又称基类或者超类;
子类又称继承类或者派生类;子类可以从它的父类中继承可访问的数据域和方法,还可以添加新的数据域和方法。
3.设计一个小程序(GeometricObject、Circle、Rectangle)
public class TestCircleRectangle {
public static void main(String[] args){
Circle circle = new Circle(1);
System.out.println("A circle "+ circle.toString());
System.out.println("The color is " + circle.getColor());
System.out.println("The radius is" + circle.getRadius());
System.out.println("The area is " + circle.getArea());
System.out.println("The diameter is " + circle.getDiameter());
Rectangle rectangle = new Rectangle(2,4);
System.out.println("\nA rectangle " + rectangle.toString());
System.out.println("The area is " + rectangle.getArea());
System.out.println("The perimeter is " + rectangle.getPerimeter());
}
}
class GeometricObject{ //父类
private String color = "write"; //私有数据域color 和 filled 不能被除了父类本身之外的其他任何类访问
private boolean filled; //读取和改变color与filled的唯一方法就是通过它们的获取方法和设置方法
private java.util.Date dateCreated; //对象创建的日期
public GeometricObject(){ //创建一个GeometricObject
dateCreated = new java.util.Date();
}
public GeometricObject(String color,boolean filled){ //创建一个带特殊颜色和填充物的GeometricObject
dateCreated = new java.util.Date();
this.color = color;
this.filled = filled;
}
public String getColor(){
return color; //返回颜色
}
public void setColor(String color){
this.color = color; //设置新的颜色
}
public boolean isFilled(){
return filled; //返回filled的属性(false or true)
}
public void setFilled(boolean filled){
this.filled = filled; //设置filled新的属性
}
public java.util.Date getDateCreated(){
return dateCreated; //返回dateCreated
}
public String toString(){ //返回这个对象的字符串表述
return "created on " + dateCreated + "\ncolor: " + color + "and filled: " + filled;
}
}
class Circle extends GeometricObject{ //子类
private double radius;
public Circle() {
}
public Circle(double radius){
this.radius = radius;
}
public Circle(double radius,String color,boolean filled){
this.radius = radius;
setColor(color); //直接调用父类的
setFilled(filled);
}
public double getRadius(){
return radius;
}
public void setRadius(double radius){
this.radius = radius;
}
public double getArea(){
return radius *radius *Math.PI;
}
public double getDiameter(){
return 2*radius;
}
public double getPerimeter(){
return 2*radius *Math.PI;
}
public void printCircle(){
System.out.println("The circle is created " +getDateCreated() +
" and the radius is " + radius);
}
}
class Rectangle extends GeometricObject{ //子类
private double width;
private double height;
public Rectangle(){
}
public Rectangle(double width,double height){
this.width = width;
this.height = height;
}
public Rectangle(double width,double height,String color,boolean filled){
this.width = width;
this.height = height;
setColor(color);
setFilled(filled);
}
public double getWidth(){
return width;
}
public void setWidth(double width){
this.width = width;
}
public double getHeight(){
return height;
}
public void setHeight(double height){
this.height = height;
}
public double getArea(){
return width * height;
}
public double getPerimeter(){
return 2 * (width + height);
}
}
4.子类和父类的区别
通过这个小程序我们来具体了解一下父类和子类
1.子类不是父类的一个子集,子类通常比父类包含更多的信息和方法。
2.父类中的私有数据域在该类之外不可以访问。
例如:上面小程序中父类中定义的 color 和 filled属性。
3.子类和它的父类形成了一种(is-a)关系;
不是所有的“是一种”(is-a)关系都应该用继承来建模。
4.一个java类只可能直接继承自一个父类;这种限制称为单一继承。
如果使用extends关键字来定义一个子类,它只允许有一个父类。
5.某些程序设计语言允许从几个类派生出一个子类,这种能力称为多重继承;
but!!!在java中不允许多重继承,*~*不过多重继承可以通过借口来实现哦。
第二部分:使用super关键字
1.关键字super
1. 关键字super指代父类,可以用于调用父类中的普通方法和构造方法。
对比学习:
关键字this它是对调用对象的引用;
关键字super指向该super所在的类的父类。
super可以用于两种途径:
1>调用父类的构造方法;
2>调用父类的普通方法。
2.调用父类的构造方法
1.构造方法用于构建一个类的实例;
不同属性和普通方法,父类的构造方法不会被子类继承,它们只能使用关键字super从子类的构造方法中调用。
调用父类构造方法的语句
super( ) 或者 super(arguments)
1.语句super( )调用父类的无参构造方法;
2.语句super(arguments)调用与arguments匹配的父类的构造方法;
3.语句super( )或者语句super(arguments)必须出现在子类构造方法的第一行,这是显示调用父类构造方法的唯一方式。
用上面的小程序我们来举个例子
public Circle(double radius,String color,boolean filled){
super(color,filled);
this.radius = radius;
3.构造方法链
1.构造方法可以调用重载的构造方法或者其父类的构造方法;如果它们都没有被显示的调用,编译器就会自动放置super()作为构造方法的第一条语句。
图
2.理解构造方法链
在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。
当构造一个子类的对象时,子类的构造方法会在完成自己的任务之前,首先调用其父类的构造方法。
如果父类继承自另一个类,那么父类的构造方法又会在完成自己的任务之前,调用其父类的构造方法。
这个过程持续到沿着这个继承层次结构的最后一个构造方法被调用为止;
这就称为构造方法链。
下面我们通过这个代码来了解了解*~*
public class Faculty extends Employee{
public static void main(String[] args){
new Faculty();
}
public Faculty(){
System.out.println("(4) performs Faculty's tasks");
}
}
class Employee extends Person{
public Employee(){
this("(2) invokes employee's overloaded constructor");
System.out.println("(3) performs employee's tasks ");
}
public Employee(String s){
System.out.println(s);
}
}
class Person {
public Person(){
System.out.println("(1) performs person's tasks");
}
}
输出:
(1) performs person's tasks (2) invokes employee's overloaded constructor (3) performs employee's tasks (4) performs Faculty's tasks
为什么是这样的输出呢??!
我们来看一张图就明白啦
注意!!:如果要设计一个可继承的类,最好为每个类提供一个无参构造方法,使得该类容易继承,同时可以避免错误。
4.调用父类的普通方法
关键字super不仅可以引用父类的构造方法,也可以引用父类的方法。
语法:
super.method(arguments);
做一道题加强记忆
class AA{
public AA() {
System.out.println("AA's no-arg constructor is invoked");
}
}
class B extends AA {
}
public class C {
public static void main(String[] args){
B b = new B();
}
}
可以尝试看看这个程序的输出,并且了解每一步是如何执行的*~*
第三部分:方法重写
1.方法重写的定义
子类从父类继承方法。有的时候呢,子类需要修改父类中定义的方法的实现,这就被称为方法重写。
举个小例子:
我们可以在本文的第一个小程序的Circle类中加入下面这段代码:
public class Circel extends GeometricObject{
/*
已经存在了的方法
*/
public String toString(){
return super.toString()+"\nradius is " + radius;
}
}
把第一个小程序拿来看,可以发现*~*
toString( )方法在GeometricObject类中定义并且在Circle类中修改了;
这两个方法都可以在Circle类中使用。
如果你想在Circle类中调用定义在GeometricObject中的toString方法,
使用语句:super.toString( ) 就okk啦!
2.重写方法的注意点
1.重写的方法必须与被重写的方法具有一样的签名,以及一样或者兼容的返回类型。
兼容的含义是:重写方法的返回类型可以是被重写方法的返回类型的子类型。
2.仅当实例方法可访问的时候,它才可以被重写。
因为私有方法在它自身之外是不能访问的,所以它不能被重写;
如果子类中定义的方法在父类中是私有的,那么这两个完全没有关系。
3.与实例方法一样,静态方法也能被继承,但是,静态方法不能被重写。
如果父类中定义的静态方法在子类中被重新定义,那么在父类中定义的静态方法将会被隐藏。
可以使用语法:SuperClassName.staticMethodName 调用隐藏的静态方法。
第四部分:方法重写与方法重载
1.方法重写与方法重载的区别①
重载意味着使用同样的名字但是不同的签名来定义多个方法;
重写意味在子类中提供一个对方法的新的实现。
2.设计一个小程序具体了解方法重载
public class TestOverloading {
public static void main(String[] args){
AAA a = new AAA();
a.p(10);
a.p(10.0);
}
}
class BBB {
public void p(double i){
System.out.println(i*2);
}
}
class AAA extends BBB{
public void p(int i){
System.out.println(i);
}
}
输出:
10
20.0
小小解析:
a.p(10)调用类A中定义的p(int i)方法,所以输出10;
a.p(10.0)调用B中定义的p(double i)方法,所以输出20.0.
3.方法重写和方法重载的区别②
1.方法重写发生在具有继承关系的不同类中;
方法重载可以发生在同一个类中,也可以发生在具有继承关系的不同类中。
2.方法重写具有同样的签名;
方法重载具有同样的名字但是不同的参数列表。
4.重写标注
为了避免错误,可以使用一种特殊的Java语法,称为重写标注;
在子类的方法前面放一个@Override
public class Circel extends GeometricObject{
/*
已经存在了的方法
*/
@Override //重写标注
public String toString(){
return super.toString()+"\nradius is " + radius;
}
}
@Override表示被标注的方法必须重写父类的一个方法。
如果具有该标注的方法没有重写其父类的方法,编译器会报一个错误。
第五部分:Object类及其toString( )方法
1.java.lang.Object类
Java中的所有类都继承自java.lang.Object类。
如果在定义一个类的时候没有指定继承,那么这个类的默认父类就是Object。
举个例子:
平时见到的String、StringBuilder、Loan和GeometricObject这样的类都隐式的是Object的子类。
2.Object类中的toString( )方法
1.toString( )方法的签名
public String toString( )
调用一个对象的toString( )会返回一个描述该对象的字符串。
一般情况下:会返回一个由该类对象所属的类名、at符号(@)以及用十六进制形式表示的该对象的内存地址组成的字符串。
第六部分:多态
1.面向对象程序设计的三大支柱
①封装
②继承
③多态
使用父类型对象的地方都可以使用子类型对象,这就是多态,多态其实就是多种形式。
多态意味着父类型的变量可以引用子类型的对象。
2.继承关系使子类能继承父类的特征,并加入一些新的特征。
子类是父类的特殊化,每个子类的实例都是其父类的实例,但是反过来不成立哦;
比如呢:
每个圆都是几何对象,但并非每个几何对象都是圆;
因此,总可以将子类的实例传给父类型参数。
2.通过小程序具体了解多态
public class PolymorphismDemo {
public static void main(String[] args){
displayObject(new Circle(1,"red",false));
displayObject(new Rectangle(1,1,"black",true));
}
//具有GeometricObject类型的参数,可以通过传递任何一个GeometricObject的实例(eg:3,4行的实例)
public static void displayObject(GeometricObject object){
System.out.println("Created on " + object.getDateCreated()+
".Color is " + object.getColor());
}
}
第七部分:动态绑定
1.通过一个简短的代码来了解动态绑定
Object book = new GeometricObject( );
System.out.println(book.toString( ));
上面的代码中toString()方法是在Object类中定义的,然而呢它在GeometricObject( )类中重写的;所以这里的book调用的是哪个toString()呢??
2.声明类型和实际类型
①声明类型
一个变量必须被声明为某种类型;声明变量的这个类型就称为变量的声明类型。
所以呢,上面book的声明类型就是Object( )类。
一个引用类型变量可以持有null值或者是一个对声明类型实例的引用;
实例可以使用声明类型或其子类型的构造方法创建。
②变量的实际类型
变量的实际类型是运行时被变量引用的对象的实际类。
所以呐,上面book的实际类型就是GeometricObject( )类,
因为book引用使用new GeometricObject( )创建的对象。
*~*book调用哪个toString( )方法由book的实际类型【GeometricObject( )类】决定,这就是动态绑定哦。
3.了解动态绑定工作机制
4.通过小程序演示动态绑定
public class DynamicBindingDemo {
public static void main(String[] args){
//类Student、Person、Object都实现了toString( )方法,使用哪个实现取决于运行时x的实际类型
m(new GraduateStudent()); // 调用 m(new GraduateStudent())时会导致定义在Student类中的toString方法被实现
m(new Student()); // 调用 m(new Student())会调用在Student类中的toString( )方法被实现
m(new Person()); // 调用 m(new Person())会调用在Person类中的toString( )方法实现
m(new Object()); // 调用 m(new Object())会调用在Object类中的toString( )方法实现
}
public static void m(Object x){ //方法m有一个Object类型的参数,可以用任何对象作为参数来调用m方法
System.out.println(x.toString());
}
}
class GraduateStudent extends Student{
}
class Student extends Person{
@Override
public String toString(){
return "Student";
}
}
class Person extends Object{
@Override
public String toString(){
return "Person";
}
}
输出:
Student
Student
Person
java.lang.Object@1be6f5c3
了解匹配方法的签名和绑定方法的实现
匹配方法的签名和绑定方法的实现是两个不同的问题。
引用变量的声明类型决定了编译时匹配哪一个方法;在编译时,编译器会根据参数类型、参数个数、参数顺序找到匹配的方法。
一个方法可能在继承链上的多个类中实现;
Java虚拟机在运行时动态绑定方法的实现,这是由变量的实际类型决定的。
第八部分:对象转换和instanceof操作符
1.对象转换
一个对象的引用可以类型转化为对另一个对象的引用,就称为对象转换。
①隐式转换
在上一个部分的代码中,有这样一个语句:
m(new Student( ));
将对象new Student( )赋值给了一个Object类型的参数;
其实呢,这条语句就等价于这两条语句:
Object book = new Student( );
m(book);
因为Student的实例也是Object的实例,
所以,语句 Object book =new Student( );是合法的哦;这就称为隐式转换。
②显示转换
思考一个问题:
可不可以使用语句: Student b = book;把对象引用book赋值给Student类型的变量??
!!!当然不可以的
因为Student对象总是Object的实例,但Object对象不一定是Student的实例。
虽然我们可以看到book实际上是一个Student对象,但是编译器不知道吖。
为了告诉编译器book是一个Student对象,就要使用显示转换。
语法:
Student b =(Student)book;
【*~*这一点点知识不太容易理解,我们通过一个生活中的例子了解一下】
可以类比水果、苹果、桃子之间的关系;
其中水果类Fruit是苹果类Apple和桃子类Peach的父类;
苹果是水果,所以总是可以将Apple的实例安全的赋值给Fruit类中的变量;
但是呢,水果不一定都是苹果,所以必须进行显示转换才可以将Fruit的实例赋值给Apple的变量。
这下就很明白啦!!
③向上转换
总是可以将一个子类的实例转换为一个父类的变量,称为向上转换。
因为呢,子类的实例总是父类的实例。
④向下转换
当把一个父类的实例转换为其子类变量时,必须显示使用转换标记进行转换,想编译器表明你的意图。
2.instanceof操作符
为了使转换成功,必须确保要转换的对象是子类的一个实例。
如果父类对象不是子类的一个实例,就会出现一个运行时异常哦。
就好比上面的例子中:
如果一个对象不是Student的实例,它就不能转换成Student类型的变量。
这里呢,有一个好办法:提前做准备法
在尝试转换之前确保该对象是另一个对象的实例,这里呢就用操作符instanceof来实现。
通过代码来了解一下
void someMethod(Object myObject){
/*code*/
if(myObject instanceof Circle){
System.out.println("The circle diameter is " + ((Circle)myObject).getDiameter( ));
/*code*/
}
}
在上面代码中,变量myObject被声明为Object类型。声明类型决定了编译是匹配那个方法。
使用myObject.getDiameter( )会出现编译错误!!!!
因为Object类没有getDiameter方法,编译器找不到和myObject.getDiameter( )匹配的方法;
所以必须将Object转换成Circle类型,这就告诉了编译器myObject也是Circle的一个实例.
3.通过小程序了解多态和类型转换
public class CastingDemo {
public static void main(String[] args){
Object object1 = new Circle(1);//使用隐式转换将一个Circle对象赋值给object1
Object object2 = new Rectangle(1,1);//使用隐式转换将一个Rectangle对象赋值给object2
displayObject(object1);
displayObject(object2);
}
public static void displayObject(Object object){
if(object instanceof Circle){ //只有源对象是目标类的实例时才能进行类型转换,在执行前程序使用instanceof来确保源对象是否是目标类的实例
System.out.println("The circle area is " +
((Circle)object).getArea()); //将Object转化成Circle类型;因为.优先于类型转换操作符,所以使用圆括号保证在访问操作符.之前进行转换
System.out.println("The circle diameter is " +
((Circle)object).getDiameter());
}
else if (object instanceof Rectangle){
System.out.println("The rectangle area is " +
((Rectangle)object).getArea());
}
}
}
①对象成员访问操作符(.)优先于类型转换操作符
对象成员访问操作符(.)优先于类型转换操作符,使用圆括号保证在访问操作符(.)之前进行转换;
例如上面代码中:
((Circle)object).getArea( );
②基本类型值的转换
对基本类型值的转换不同于对对象引用进行转换。
1>转换一个基本类型值返回一个新的值:
例如:
int shenggao = 180;
byte newShenggao = (byte)shenggao; 返回一个新值
2>转换一个对象引用不会创建一个新的对象:
例如:
Object book = new Circle();
Circle happy =(Circle)book; 没有创建一个新的对象
现在呢,引用变量 book 和happy指向同一个对象哦。
第九部分:Object类的equals方法
1.equals方法的签名
public boolean equals(Object o)
2.调用equals方法的语法
object1.equals(objects2);
这个方法测试两个对象是否相等
3.Object类中equals方法的默认实现
public boolean equals(Object obj){
return this ==obj;
}
这个实现使用==操作符来检测两个引用变量是否指向同一个对象。
所以呢,应该在自定义类中重写这个方法,用来测试两个不同的对象是否具有相同的内容。
说了这么多了,举个例子了解一下*~*
下面的代码根据圆的半径来判断两个圆是否相等
@Override
public boolean equals(Object book){
if (book instanceof Circle)
return radius ==((Circle)book).radius;
else
return false;
}
4.比较操作符==
①比较操作符==用来比较两个基本数据类型的值是否相等;
或者用来判断两个对象是否有相同的引用。
②如果equals方法在对象的定义类中被重写,其意图在与判断两个对象是否具有相同的内容;
③操作符==要比equals方法的功能强大一些,因为==操作符可以检测两个引用变量是否指向同一个对象。
5.小小注意点
在子类使用签名equals(SomeClassName obj)比如:equals(Circle c))重写equals方法是一个错误的,应该使用equals(Object obj).
第十部分:ArrayList类
1.简要介绍ArrayList类
1>.ArrayList对象可以用于存储一个对象列表。
2>.平常呢,我们可以创建一个数组来存储对象,但是这个数组一旦创建了,它的大小就是固定的。
在Java中呢就提供了ArrayList类,可以用来存储不限数目的对象。
3>.ArrayList被称为具有一个泛型类型E的泛类型;可以在创建ArrayList时指定一个具体的类型来替换E。
2.创建ArrayList的语句
我们来看两个例子就明白啦*~*
【例1】
ArrayList<String> cities = new ArrayList<String> ( );
创建一个ArrayList,并且将它的引用赋值给变量cities;这个ArrayList对象可以用于存储字符串。
【例2】
ArrayList<java.util.Date> dates = new ArrayList<java.util.Date>( );
创建一个ArrayList,并且将它的引用赋值给变量dates;这个ArrayList对象可以存储日期。
注意啦!!!
ArrayList <AConcreteType> list = new ArrayList<AConcreteType>( );
等价于
ArrayList<AConcreteType> list = new ArrayList<>( ); 【无参构造】
是因为从JDK7 开始,使用了称为类型推导的特征,构造方法中不再要求给出具体类型;编译器可以从变量的声明中推导出类型。
3.设计一个小程序使用ArrayList储存对象
import java.util.ArrayList;//因为ArrayList位于java.util包中,在第一行导入该包
public class TestArrayList {
public static void main(String[] args){
//采用无参构造方法创建一个存储字符串的ArrayList,并且将引用赋值给cityList
ArrayList<String> cityList = new ArrayList<>();
//使用add方法将字符串添加到数组末尾
cityList.add("London");
cityList.add("Denver");
cityList.add("Paris");
cityList.add("Miami");
cityList.add("Seoul");
cityList.add("Tokyo");
//调用size( )方法返回这个数组列表的大小
System.out.println("List size?" + cityList.size());
//调用contains("Miami")检查该对象是否在这个数组列表中【返回true或者false】
System.out.println("Is Miami in the list? " + cityList.contains("Miami"));
//调用indexOf("Denver")返回该对象在数组列表的下标值
System.out.println("The location of Denver in the list? " +cityList.indexOf("Denver"));
//检查该数组列表是否是空的
System.out.println("Is the list empty? " +cityList.isEmpty());
//在数组列表的制定下标位置插入一个对象
cityList.add(2,"Xian");
//从数组列表中删除对象“Miami”
cityList.remove("Miami");
//删除数组列表制定下标的元素
cityList.remove(1);
//这条语句等价于System.out.print\n(cityList)
//方法toString( )返回数组列表的字符串表示,其形式为【x1,x2,...,xn】;比如[London, Xian, Paris, Seoul, Tokyo]
System.out.println(cityList.toString());
for(int i=cityList.size()-1;i>=0;i--)
System.out.print(cityList.get(i) + " ");//get(index)返回制定下标位置处的对象
System.out.println();
ArrayList<Circle> list = new ArrayList<>();
list.add(new Circle(2));
list.add(new Circle(3));
System.out.println("The area of the circle? " + list.get(0).getArea());
}
}
4.了解数组和ArrayList类的异同
操作 | 数组 | ArrayLIst |
创建数组/数组列表 | String[ ] a =new String [10] | ArrayList list<String > =new ArrayList(( ) |
访问元素 | a [index] | list.get(index) |
更新元素 | a [index] = "London" | list.set(index,"Lodon"); |
返回大小 | a.length | list.size( ) |
添加一个新元素 | list.add("Lodon") | |
插入一个新元素 | list.add(index,"London") | |
移除一个元素 | list.remove(index) | |
移除一个元素 | list.remove(Object) | |
移除所有元素 | list.clear( ) |
注意!!!
对数组排序:java.util.Arrays.sort(array);
对数组列表排序:java.util.Collections.sort(arrayList)方法。
错误警示!!!!
①*~*
如果你想创建一个用于存储整数的ArrayList,使用下面的语句对不对呢?
ArrayList<int> listOfIntegers = new ArrayList<>( );
当然是不对哦;
因为存储在ArrayList中的元素必须是一种对象,不能使用像int的基本数据类型来代替一个泛型类型。
但是可以使用下面的方式创建:
ArrayList<Integer> listOfIntegers =new ArrayList<>( );
②*~*
remove(int index)方法移除指定下标位置的元素;要从listOfIntegers中移除一个整数值,
需要使用listOfIntegers.remove(new Integer(v));但是呢这不太好;
所以更好的是将remove(int)改名为removeAt(int).
5.小小练习
import java.util.ArrayList;
import java.util.Scanner;
public class DistinctNumbers {
public static void main(String[] args){
//创建了一个存储Integer对象的ArrayList
ArrayList<Integer> list = new ArrayList<>();
Scanner input = new Scanner(System.in);
System.out.print("Enter integers (input ends with 0): ");
int value;
do{
value = input.nextInt(); //使用循环读入数据
if(!list.contains(value) && value!=0)
list.add(value);
}while(value !=0);
System.out.print("The distinct integers are: ");
for(int i=0;i<list.size();i++)
System.out.print(list.get(i)+" ");
//for循环还可以这样写
//第一种改法
/*
for(Integer number: list)
System.out.print(number + " ");
*/
//第二种改法
/*
for(int number:list)
System.out.print(number + " ");
*/
//list中的元素是Integer对象,它们在for循环中被自动拆箱为int
}
}
这个小程序的作用是:从键盘读取一些数字,输出不同的数字;
这里呢,明明可以使用数组存储元素,但是为什么要使用数组列表(ArrayList)呢??
当然是使用数组列表更加方便呐
①ArrayList的大小是灵活的,所以不同提前设置好大小;
如果是数组的话就必须提前给定大小。
②ArrayList包含许多有用的方法,比如上面使用contains( )方法来测试某个元素是否在列表中;
如果是数组的话就需要自己设计方法。
第十一部分:关于列表的一些有用方法
1.从一个数组创建一个数组列表
例如:
String[ ] array = {"red", "green", "blue"};
ArrayList<String>list = new ArrayList<>(Arrays.asList(array));
2.Arrays类中的静态方法asList
Arrays类中的静态方法asList返回一个列表,该列表传递给ArrayList的构造方法用于创建一个ArrayList。
反过来说呢,可以使用下面的代码从一个数组列表创建一个对象数组
3.从一个数组列表创建一个对象数组
String[ ] array1 = new String[list.size( )];
list.toArray(array1);
调用list.toArray(array1)将list中的内容复制到array1中。
4.使用java.util.Collections类中的静态方法sort来对元素进行排序
如果列表中的元素是可以比较的,比如整数、双精度浮点数、字符串;就可以使用java.util.Collections类中的静态方法sort来对元素进行排序。
举个小例子:
Interger[ ] array = {1, 5, 33, 7, 2, 8};
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(array));
java.util.Collections.sort(list);
System.out.println(list);
5.使用java.util.Collections类中的静态方法max和min分别返回列表中元素的最大元素和最小元素
例如:
Interger[ ] array = {1, 5, 33, 7, 2, 8};
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(array));
java.util.Collections.max(list);
java.util.Collections.min(list);
System.out.println(list);
System.out.println(list);
6.使用java.util.Collections类中的静态方法shuffle随机打乱列表元素
比如:
Interger[ ] array = {1, 5, 33, 7, 2, 8};
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(array));
java.util.Collections.shuffle(list);
System.out.println(list);
第十二部分:自定义栈类
设计一个栈类,用来存放对象
import java.util.ArrayList;
public class MyStack {
private ArrayList<Object> list = new ArrayList<>(); //创建一个数组列表用来存储栈中的元素
public boolean isEmpty(){
return list.isEmpty(); //如果栈为空,返回true
}
public int getSize(){
return list.size(); //返回该栈中元素的个数
}
public Object peek(){
return list.get(getSize()-1); //返回栈顶元素并且不移除
}
public Object pop(){ //返回该栈的栈顶元素并且移除
Object o = list.get(getSize()-1);
list.remove(getSize()-1);
return o;
}
public void push(Object o){ //添加一个新的元素到该栈的顶部
list.add(o);
}
@Override
public String toString(){
//list.toString( )方法重写了Object类中定义的toString()方法,用来显示栈中的内容
return "stack: " + list.toString(); //ArrayList中实现的toString()方法返回表示数组列表中所有元素的字符串表示
}
}
在上面的小程序中,MyStack中包含ArrayList;MyStack和ArrayList之间的关系称为组合。
组合本质上意味着声明一个实例变量来引用一个对象;该对象称为被组合了。
继承是对“是一种”(is-a)关系建模;
组合是对“包含”(has-a)关系建模。
第十三部分:protected数据和方法
1.protected关键字
①类中受保护成员可以从子类中访问;
②平常呢,我们需要允许子类访问定义在父类中的数据域或者方法,但是不允许位于不同包中的非子类的类访问这些数据域和方法;
使用protected关键字就可以完成这个功能,父类中受保护的数据域或者方法可以在它的子类中访问。
2.可见性修饰符(可访问性修饰符)
修饰符private、protected、public都成为可见性修饰符或者可访问性修饰符。
3.数据和方法的可见性
类中成员的修饰符 | 在同一类中可访问的 | 在同一包中可访问的 | 在不同包中的子类可访问 | 在不同包中可访问的 |
public | true | true | true | true |
protected | true | true | true | false |
default(无修饰符) | true | true | false | false |
private | true | false | false | false |
1.使用private修饰符可以完全隐藏该类的成员,这样就不能从类外访问它们。
2.不使用修饰符就表示允许同一个包里的任何类直接访问该类的成员,但是其他包中的类不可以访问。
3.使用protected修饰符允许任意类访问该类的成员。
4.使用可见性修饰符访问数据和方法
修饰符private和protected只能用于类的成员。
public修饰符和默认修饰符(就是没有修饰符的)既可以用于类的成员,也可以用于类;
一个没有修饰符的类(既非公共类)不能被其他包中的类访问。
5.使用类的两种方式
①用于创建该类的实例;
②通过继承该类创建它的子类。
如果不希望从类的外部使用类的成员,就把成员声明成private;
如果想让该类的用户都能使用类的成员,就把成员声明成public;
如果想让该类的继承类使用数据和方法,但是不想让该类的用户使用,就把成员声明为protected.
6.小小注意点 (子类改父类可见性)
子类可以重写其父类的protected方法并且把父类的可见性改为public;
但是子类不可以削弱父类中定义的方法的可访问性。
举个例子:
如果一个方法在父类中定义为public,在子类中也必须定义为public。
第十四部分:防止继承和重写
1.用final修饰的类和方法不能被继承
用final修饰的类和方法不能被继承;用final修饰的数据域是一个常数。
2.最终类
在希望防止类被继承的情况下,使用final修饰符表明一个类是最终类,从而这个类就不能作为父类。
Math是最终类,String、StringBuilder、StringBuffer类以及所有基本数据类型的包装类也都是最终类。
例1:定一个最终类
public final class A {
//code
}
类A就是最终类,不能被继承
例2:定义一个方法为最终的,最终方法不能被其子类重写
public class Temp {
//code
public final void m( ) {
//code
}
}
方法m是最终的,不能被重写
*~*
修饰符public 、private、protected 、static 、abstract 以及final都可以用在类和类的成员(数据和方法)上 ,只有final修饰符还可以用在方法中的局部变量上,方法内的final局部变量就是常量。
海压竹枝低复举,风吹山脚晦还明^_^
大家共勉哦