文章目录
面向对象:
什么是对象:
一切客观存在的物体统称为对象。
对象的组成:
1.属性 ;数据类型 变量名 [=值 ];
2.方法 ;[访问修饰符] 返回值类型 方法名字([参数列表]){代码块;}
类是什么:
1.类是对大量对象共性的抽象
2.类是创建对象的模板
类的组成:
1.属性;
2.方法;
类的创建语法
[public] class 类名{
[成员变量];
[成员方法];
}
类的使用:
使用类必须为类创建对象:
语法
类型 变量名 = new 类类型名();
如 Student stu = new Student();
调用属性:
对象名.属性名[= 值];
调用方法:
对象名.方法名();
方法的重载:
1.方法名一致,参数列表不同的方法就是方法的重载。
2.重载必须发生在同一个类里面
构造方法:构造函数,构造器
1.任何类都必须要有构造器。
2.如果类里面没有声明构造器,计算机默认提供一个午餐的构造器
3.构造器不能返回值类型。
4.构造器的方法名必须和类名一致。
5.构造方法只能跟在new的后面来创建对象.
构造器的语法:
[public] 类名([参数列表]){ 方法体; }
对象的引用:
Student s; s = new Student();
引用存储的是对象内存空间的首地址
this关键字:
- this是一种特殊的引用,指向当前对象
- 如果发生局部变量可以成员变量命名冲突时,可以通过this.成员变量名的方式区分实例变量和局部变量
- 一个构造方法中需要调用同一个类的另一个构造方法,可以通过this()的方式调用,但this()必须要书写在第一行
OOP练习:
练习一
创建一个圆Circle类,为该类提供两个方法,方法一用于求圆的面积,方法二用于求圆的周长,同时为该类提供一个变量r表示半径,一个常量PI表示圆周率。
为该类提供一个无参的构造方法,用于初始化r的值为1;且提供一个有参的构造方法,参数用于初始化半径r的值
案例代码:
public class Circle {
//属性:
double r;
//常量
final double PI=3.14;
//方法:
//构造方法
public Circle(){
r=1;//默认半径为1
}
//方法的重载
public Circle(double r){
this.r=r;
}
//面积
public double area(){
return PI*r*r;
}
//周长
public double perimeter(){
return 2*PI*r;
}
}
练习二
饲养员类,动物类,食物类。实现饲养员给动物喂食物。
案例代码:
//食物类
public class Food {
//属性:
String type;
//提供构造方法
public Food(){}
public Food(String type){
this.type=type;
}
}
//动物类:
public class Animal {
//属性:
String type;
//构造方法:
public Animal(){}
public Animal(String type){
this.type = type;
}
//方法:
//吃的方法
public void eat(Food food){
System.out.println(type+"正在吃"+food.type);
}
}
//饲养员类
public class Feeder {
//属性:
Animal animal;
Food food;
//方法:
//构造方法:
public Feeder(){}
public Feeder(Animal animal,Food food){
this.animal=animal;
this.food=food;
}
public void feed(){
animal.eat(food);
}
public static void main(String[] args) {
//创建对象
Food food=new Food("狗粮");
Animal animal=new Animal("狗");
Feeder feeder=new Feeder(animal,food);
feeder.feed();//饲养员喂动物
}
}
练习三:
创建一个账户Account类,该类有id:账户号码(长整数),password:账户密码,name:真实姓名,personId:身份证号码 字符串类型,email:客户的电子邮箱,balance:账户余额.
方法:deposit: 存款方法,参数是double型的金额;
withdraw:取款方法,参数是double型的金额.
构造方法:有参和无参,有参构造方法用于设置必要的属性
案例代码:
public class Account {
//属性:
long id;
int password;
String name;
String personId;
String email;
double balance;
//方法:
//构造方法
public Account(){}
public Account( long id,int password,String name,String personId,String email, double balance){
this.id=id;
this.password=password;
this.name=name;
this.email=email;
this.personId=personId;
this.balance=balance;
}
//方法:
//存款
public void deposit(double money){
balance+=money;//balance=balance+money;
System.out.println("该银行卡存入"+money+"钱之后,余额是"+balance);
}
//取款
public void withdraw(double money){
//先进行判断余额是否够取出
if(money <= balance){
balance-=money;
System.out.println("该银行卡取出"+money+"钱之后,余额是"+balance);
}else{
System.out.println("余额不足!!!!");
}
}
}
static关键字的使用:
类的组成:属性(成员变量)和方法(成员方法)
- 成员变量分为类变量和实例变量
- 成员方法分为类方法和实例方法
- 类变量:使用关键字static修饰的变量
- 类方法:使用关键字static修饰的方法
实例变量和类变量的区别:
- 所有该类的对象共享同一个类变量,但是每个对象都会有自己独特的实例变量
- 所有该类的对象都能改变类变量的值,但是每个对象只能改变自己的实例变量值
- 实例变量在使用前必须创建一个对象,根据对象名.变量名使用,但是类变量不需要创建对象,可以通过类名.变量名或类名.方法名直接调用。
- 实例方法当中可以直接调用类变量和实例变量。
- 类方法只能直接调用类变量,如果要想调用实例对象必须先为实例变量创建对象。
public class StaticTest {
//属性
String name;//实例变量
static int age;//类变量
//方法
public void say(){//实例方法
System.out.println("这是我得自我介绍!!!我得名字是:"+name+"我得年龄是:"+age);
}
public static void eat(){//类方法
StaticTest test=new StaticTest();
System.out.println("我得名字是:"+test.name+"我得年龄是:"+age);
System.out.println("我是一个吃货");
}
public static void main(String[] args) {
//创建对象
StaticTest test1=new StaticTest();
test1.name="张三";
test1.age=18;
System.out.println("我得名字是"+test1.name+",我得年龄是:"+test1.age);
StaticTest test2=new StaticTest();
test2.age=20;
System.out.println("我得名字是"+test2.name+",我得年龄是:"+test2.age);//
StaticTest test3=new StaticTest();
System.out.println("我得名字是"+test3.name+",我得年龄是:"+test3.age);
System.out.println("StaticTest的年龄是:"+StaticTest.age);
}
}
静态代码块:
是一个以static为前导的代码块,一般用于为类的工作做一些初始化工作
访问修饰符的使用:
访问修饰符主要用来修饰方法和变量
访问修饰符 | 作用范围 | |||
---|---|---|---|---|
private | 本类 | |||
default | 本类 | 同包下的其他类 | ||
protected | 本类 | 同包下的其他类 | 其他包下的子类 | |
public | 本类 | 同包下的其他类 | 其他包下的子类 | 其他包下的其他类 |
封装:面向对象程序设计的三大特征之一
把客观事物封装成抽象的类,并且类可以把自己的属性和方法只让可信的类
或者对象进行操作,对不可信的类或者对象隐藏,这样的过程叫做封装。
代码演示:
public class Student {
//属性:1.封装:把我们的属性私有化
private int stuNo;//学号
private String stuName;//名字
private int age;//年龄
//方法:
//2.给私有化的属性提供getter和setter方法:
public void setStuNo(int stuNo){//给学号赋值
if (stuNo <0){
System.out.println("该学号是无效的,没有办法赋值!!!");
this.stuNo=0;
}else{
this.stuNo=stuNo;
}
}
public int getStuNo(){//获取学号
return stuNo;
}
public void setStuName(String stuName){
this.stuName=stuName;
}
public String getStuName(){
return stuName;
}
public void setAge(int age){
if(age >=0 && age <=150 ){
this.age=age;
}else{
System.out.println("你的年龄是无效的。");
this.age=0;
}
}
//自我介绍:
public void display(){
System.out.println("我是一名学生,\n我的学号是:"+stuNo+"\n我的姓名是:"+stuName+"\n我的年龄:"+age);
}
}
//测试类
class Test{
public static void main(String[] args) {
//创建学生对象
Student student=new Student();
student.setStuNo(12345);
student.setStuName("张三");
student.setAge(-12);
// student.stuNo=12345;
// student.stuName="张三";
// student.age=-20;
student.display();
}
}
实验练习:
创建一个图书Book类,该类有属性:
书名、作者、出版社、价格等。
将该类各属性进行封装,并为各属性提供getter和setter方法。
通过公有的get/set方法实现属性的访问,其中:
1、限定图书价格必须大于10,如果无效需进行提示,并强制赋值为10
2、限定作者、书名均为只读属性
案例代码:
//图书类:
public class Book {
//属性:
private String bookName;
private String author;
private String press;
private double price;
//方法:
//构造方法
public Book(){}
public Book(String bookName,String author){
this.bookName=bookName;
this.author=author;
}
//提供getter和setter方法:
public String getBookName(){
return bookName;
}
public String getAuthor(){
return author;
}
public void setPress(String press){
this.press=press;
}
public String getPress(){
return press;
}
public void setPrice(double price){
if (price > 10){
this.price=price;
}else{
System.out.println("你得价格是无效的!!!");
this.price=10;
}
}
public double getPrice(){
return price;
}
}
class Test1{
public static void main(String[] args) {
//创建图书对象
Book book=new Book("红楼梦","曹雪芹");
book.setPrice(-10);
book.setPress("人民大学出版社");
//打印图书的信息
System.out.println("图书简介:\n书名:"+book.getBookName()+"\n作者:"+
book.getAuthor()+"\n出版社:"+book.getPress()+"\n价格:"+book.getPrice());
}
}
继承:面向对象的三大特征之一
一个新类可以从现有的类派生,这样的过程叫做继承。
那么在继承的过程中,新类被称为子类,现有的类被称为父类,子类将会继承父类非私有的属性和行为。
继承的语法:
[访问修饰符] class 子类的类名 extends 父类的类名{ 成员变量;成员方法;}
继承的特点:
1.子类除了可以拥有父类非私有的属性和方法外,也可以扩展自己的属性和方法
2.Java中类的继承是单继承,也就是一个类只能有一个父类
3.Java中类的继承具有传递性。
(A继承B)(B继承了C)(A具有了B和C 所有非私有的属性和方法)
4.任何类都有父类,如果我们没有声明父类,默认继承了我们Object类.
5.子类无法继承父类的构造方法,子类在创建对象的时候都会先去调用父类的构造方法。
方法的重写:@Override
当从父类中继承过来的方法不能满足子类需要时,子类就要对方法进行重新编译。这就叫做方法的重写
重写的特点:@Override
1.只能发生在子类继承父类的子类里面。
2.子类重写的方法访问修饰符不能严于父类。
3.重写的返回值类型,方法名和参数列表都必须和父类保持一致。
重载的特点:@Overload
1.只能发生在同一个类里面
2.只要求方法名相同,参数列表不同,和其他内容没有关系。
super关键字:
1.super代表了父类的对象
2.super.属性名:子类中调用父类被隐藏的同名实例变量
3.super([参数列表]):用来调用父类的构造方法。
而且必须放在第一行。(子类一定会调用父类的构造方法)
this关键字:
1.this代表了本类的对象
2.this.属性名:当全局变量和局部变量重名,代表了全局变量
3.this([参数列表]):用来调用本类的构造方法,而且必须放在第一行。
final关键字:
final关键字可以用来修饰类、变量和方法。有不可更改或最终的含义。
final修饰的类称之为最终类,不能被继承。
final修饰的方法称之为最终方法,可以被继承不能被重写
final修饰的变量称之为常量,值不能被更改,而且必须在声明的时候进行赋值。
实验练习1:
设计一个形状类Shape,方法:求周长(girth)和求面积(area)
形状类的子类:Rect(矩形),Circle(圆形),不同的子类会有不同的计算周长和面积的方法
实验练习2:
某公司的雇员分为以下若干类:
Employee:这是所有员工总的父类,属性:员工的姓名,员工的生日月份。方法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日,则公司会额外奖励100元。
SalariedEmployee:Employee的子类,拿固定工资的员工。属性:月薪(monthSalary)
HourlyEmployee:Employee的子类,按小时拿工资的员工,每月工作超出160小时的部分按照1.5倍工资发放。属性:每小时的工资(hourSalary)、每月工作的小时数(hour)
SalesEmployee:Employee的子类,销售人员,工资由月销售额和提成率决定。属性:月销售额(monthSales )、提成率(commissions)
BasePlusSalesEmployee:SalesEmployee的子类,有固定底薪的销售人员,工资由底薪加上销售提成部分。属性:底薪(baseSalary)。
多态:面向对象的三大特征之一
客观存在的物体的多种形态。
java中多态的实现:
1.继承或者实现关系
2.方法重写
3.向上转型
多态的实验案例:
//动物园有这些动物:狗、兔子等,
//饲养员每天都会给这些动物喂食,
//狗喜欢吃骨头、而兔子喜欢吃胡萝卜,
//通过Java程序模拟饲养员喂食
//父类:动物类
class Animal{
//吃
public void eat(){
System.out.println("吃东西!!!");
}
}
//狗类
class Dog extends Animal{
//吃
public void eat(){
System.out.println("吃骨头!!!!");
}
//看门
public void seeDoor(){
System.out.println("吃饱了之后去看门!!!!");
}
}
//兔子类
class Rabbit extends Animal{
//吃
public void eat(){
System.out.println("吃红萝卜!!!!");
}
//睡觉
public void sleep(){
System.out.println("吃饱了之后就睡觉!!!!");
}
}
// 猫
class Cat extends Animal{
//吃
public void eat(){
System.out.println("吃鱼!!!");
}
//抓耗子
public void catchMouse(){
System.out.println("吃饱之后去抓耗子!!!!");
}
}
//饲养员的类
class Feeder{
//喂食
public void feed(Animal animal){
animal.eat();
//向下转型
if(animal instanceof Dog){
//向下转型(强制转换)
Dog dog=(Dog) animal;
dog.seeDoor();
}else if(animal instanceof Rabbit){
Rabbit rabbit =(Rabbit) animal;
rabbit.sleep();
}else if(animal instanceof Cat){
Cat cat=(Cat) animal;
cat.catchMouse();
}
}
/* public void feed(Dog dog){
dog.eat();
}
public void feed(Rabbit rabbit){
rabbit.eat();
}
public void feed(Cat cat){
cat.eat();
}*/
}
class Test{
public static void main(String[] args) {
//饲养员给动物喂食物的过程
Feeder zhangSan=new Feeder();
//创建动物对象:向上转型 父亲:教毛概 儿子:教经济学 看电影
Animal dog=new Dog(); // 父亲 = new 儿子();
// 讲课:教经济学
Animal rabbit=new Rabbit();//回家:向下转型
Animal cat=new Cat();
// Dog dog=new Dog();
// Rabbit rabbit=new Rabbit();
zhangSan.feed(rabbit);
}
}
多态的优势:
1.提高代码的重用
2.降低耦合度
instanceof运算符:
判断对象是否属于某个类。
import关键字:
用来引入我们某些类。
import 包.类名;
导入包的实验案例:
- 猜数字的小案例:
- 随机数产生一个答案,通过键盘输入进行猜测:
猜测的数过大:提示猜测的数字过大,重新猜
猜测的数过小:提示猜测的数字过小,重新猜
猜对了:提示恭喜过关!!!
public class ImportTest {
//随机数产生一个答案
private static int num;
//静态代码块:
static {
Random random=new Random();
num = random.nextInt(100);
}
public static void main(String[] args) {
//创建键盘输入的类
Scanner sc=new Scanner(System.in);
//提示语句
System.out.println("请输入您猜测的答案:");
while(true) {
//接收键盘输入
int i = sc.nextInt();
//判断猜测的结果是否正确
if (i > num) {
System.out.println("猜大了,请重新猜!!!");
}else if(i < num){
System.out.println("猜小了,请重新猜!!!");
}else{
System.out.println("恭喜您答对啦!!!欢迎过关!!!");
break;//跳出循环
}
}
}
}
包
包就是用来将Java中类和接口等进行分类管理的工具,类似于操作系统中的目录
包的声明:package
package 包名;
包名的前半部分一般使用倒置的域名,后半部分一般采用该包下类分类名(或者功能名)。
如:
package com.java.util;
package com.java.dao;
包的声明必须是整个类文件的第一行语句
抽象类和抽象方法
抽象方法:abstract抽象的.
对于某些方法没有具体的实现过程,而且子类肯定回重写这个方法,出于对项目的优化,把方法声明称抽象方法
抽象方法的声明:
[修饰符] abstract 返回值类型 方法名([参数列表]);
注意:因为抽象方法无法确定具体执行的功能,所有抽象方法没有方法体,需要在小括号后加上分号
抽象类:abstract抽象的
对于我们的抽象方法,普通的类没有办法声明,需要把我们的类也声明为抽象的 。这样类叫做抽象类.
抽象类的语法:
[修饰符] abstract class 类名 [extends 父类名]{类体}
抽象类优点:优化代码,优化性能.
1.存在抽象方法的类后一定是抽象类。
2.抽象类可以放普通方法。(抽象类也可以只有普通方法)
3.抽象类不可以直接创建对象。
如果想要创建对象只能创建子类的对象
4.子类继承了抽象类,必须重写抽象类里面所有的抽象方法。
5.抽象类也可以使用多态。
抽象类的实验案例练习:
设计一个形状类(抽象类)Shape,方法:求周长和求面积
形状类(抽象类)的子类:Rect(矩形),Circle(圆形),Square(正方形),不同的子类会有不同的计算周长和面积的方法,创建三个不同的形状对象,放在Shape类型的数组里,分别打印出每个对象的周长和面积
接口:
接口不仅仅是程序开发过程中“约定”,更是更加抽象化的抽象类.
接口的声明语法:interface关键字
[访问修饰符] interface 接口名{
[public] [static] [final] 数据类型 常量名字 =值;
[public] [abstract] 返回值类型 方法名([参数列表]);
}
JDK1.8以后特性:
//使用默认修饰符修饰的方法:
default void say(){
System.out.println("JDK1.8的特性,可以使用默认方法!!!");
}
//还可以声明静态方法:
public static void display(){
System.out.println("jdk1.8以后接口可以使用静态方法!!!!");
}
接口的使用:implements关键字
[访问修饰符] class 类名 implements 接口名{}
接口的特点:
1.接口不能创建对象,可以创建实现类的对象.
2.实现类实现接口的时候,必须重写接口里面所有的抽象方法。
3.实现类实现接口的时候可以实现多个接口.(多实现)
4.接口可以继承接口.一个子接口可以继承多个父接口(多继承)
接口的优势:
1.提高程序的重用性
2.提高程序可扩展性
3.降低程序的耦合度
4.接口实现了多继承.
接口的使用案例:
此时有一个学生张三:包含了学号,包含姓名,喜欢学习线性代数,喜欢抽烟,喜欢喝酒,喜欢打游戏.
public abstract class Student {
//属性:
private int stuNo;
private String stuName;
//方法:
//构造方法
public Student(){}
public Student(int stuNo,String stuName){
this.stuNo=stuNo;
this.stuName=stuName;
}
//提供getter和setter方法
public void setStuNo(int stuNo){
this.stuNo=stuNo;
}
public int getStuNo(){
return stuNo;
}
public void setStuName(String stuName){
this.stuName=stuName;
}
public String getStuName(){
return stuName;
}
//学习的方法
public abstract void study();
}
//接口代表能力
interface Smoking{
//抽烟
void smoke();
}
interface Drinking{
//喝酒
void drink();
}
interface Game{
//游戏
void play();
}
//创建具有功能特点的学生
class ZhangSan extends Student implements Smoking,Drinking,Game{
//构造方法
public ZhangSan(){}
public ZhangSan(int stuNo,String stuName){
super(stuNo,stuName);
}
@Override
public void study() {
System.out.println(getStuName()+"喜欢学习线性代数!!");
}
@Override
public void smoke() {
System.out.println("喜欢喝飞天茅台!!!!");
}
@Override
public void drink() {
System.out.println("喜欢抽冬虫夏草!!!!");
}
@Override
public void play() {
System.out.println("喜欢玩儿LOL");
}
}
//有一个学生李四:不喜欢学习,喜欢玩儿游戏
class LiSi extends Student implements Game{
//构造方法
public LiSi(){}
public LiSi(int stuNo,String stuName){
super(stuNo, stuName);
}
@Override
public void study() {
System.out.println(getStuName()+"不喜欢学习,就喜欢睡觉!!");
}
@Override
public void play() {
System.out.println("喜欢玩植物大战僵尸!!!");
}
}
class Test{
public static void main(String[] args) {
//创建张三这个学生
ZhangSan zhangSan=new ZhangSan(1001,"张三");
zhangSan.study();//学习
zhangSan.smoke();//抽烟
zhangSan.drink();//喝酒
zhangSan.play();//玩游戏
System.out.println();
LiSi liSi=new LiSi(1002,"李四");
liSi.study();
liSi.play();//玩游戏
}
}
接口的专项练习:
1.普通的手机(CommonHandset),可以发短信,通电话。随着发展,智能手机(AptitudeHandset ),增加了功能:音频、视频播放(PlayWiring )、拍照(TheakePictures )、上网(Network )
//手机:
public abstract class HandSet {
//属性:
private String type;//型号
private String brand;//品牌
//方法:
//提供构造方法
public HandSet(){}
public HandSet(String type,String brand){
this.type=type;
this.brand=brand;
}
//提供getter和setter方法
public void setType(String type){
this.type=type;
}
public String getType(){
return type;
}
public void setBrand(String brand){
this.brand=brand;
}
public String getBrand(){
return brand;
}
//描述手机基本信息
public void display(){
System.out.println("这是一款型号为"+type+"的"+brand+"手机......");
}
//打电话
public abstract void call();
//发短信
public abstract void sendInfo();
}
//音频和视频的播放:
interface PlayWiring{
//播放功能:
void play(String content);
}
//拍照接口
interface TheakePictures{
//拍照功能
void takePicture();
}
//联网:
interface Network{
//联网功能
void netWorkConn();
}
//创建手机类:
class CommonHandset extends HandSet implements PlayWiring{
//提供构造方法:
public CommonHandset(){}
public CommonHandset(String type,String brand){
super(type, brand);
}
@Override
public void call() {
System.out.println("开始语音通话......");
}
@Override
public void sendInfo() {
System.out.println("发送文字信息......");
}
@Override
public void play(String content) {
System.out.println("开始播放音乐《"+content+"》.....");
}
}
//智能手机:
class AptitudeHandset extends HandSet implements PlayWiring,Network,TheakePictures{
//构造方法:
public AptitudeHandset(){}
public AptitudeHandset(String type,String brand){
super(type, brand);
}
@Override
public void call() {
System.out.println("开始视频通话......");
}
@Override
public void sendInfo() {
System.out.println("开始发送带有文字和图片的信息.....");
}
@Override
public void play(String content) {
System.out.println("开始播放视频《"+content+"》.....");
}
@Override
public void takePicture() {
System.out.println("咔嚓.......拍照成功!!!!");
}
@Override
public void netWorkConn() {
System.out.println("已经启动网络连接......");
}
}
//测试类:
class Test{
public static void main(String[] args) {
//购买两款手机
CommonHandset commonHandset=new CommonHandset("G502c","索尼爱立信");
commonHandset.display();//出厂信息
commonHandset.play("热雪");//播放音乐
commonHandset.sendInfo();//发短信
commonHandset.call();//打电话
AptitudeHandset aptitudeHandset=new AptitudeHandset("I9100","HTC");
aptitudeHandset.display();//出厂信息
aptitudeHandset.netWorkConn();//链接网络
aptitudeHandset.play("小时代");//播放视频
aptitudeHandset.takePicture();//拍照
aptitudeHandset.sendInfo();//发信息
aptitudeHandset.call();//打电话
}
}
2.设计一个台灯类Lamp其中台灯有灯泡这个属性,还有开灯(on)这个方法,设计一个灯泡类,其中有红灯泡(RedBuble) 和绿灯泡(GreenBuble),他们都有一个发亮的方法,请设计出一段代码可以使台灯开启灯泡发亮,并且保证替换不同种类的灯泡台灯类代码不被修改。
//灯泡接口
interface Buble{
//发光:
void light();
}
//红灯泡
class RedBuble implements Buble{
@Override
public void light() {
System.out.println("发红光!!!!!");
}
}
//绿灯泡
class GreenBuble implements Buble{
@Override
public void light() {
System.out.println("发绿光");
}
}
//台灯类
public class Lamp {
//属性:
private Buble buble;
//提供构造方法:
public Lamp(){}
public Lamp(Buble buble){
this.buble=buble;
}
//提供gterter和setter方法:
public void setBuble(Buble buble){
this.buble=buble;
}
public Buble getBuble(){
return buble;
}
//开关:
public void on(){
buble.light();
}
}
//测试类:
class TestLamp{
public static void main(String[] args) {
//购买灯泡:多态
Buble buble1=new RedBuble();
Buble buble2=new GreenBuble();
//组装台灯
Lamp lamp=new Lamp(buble2);
//开灯
lamp.on();
}
}
//抽象类方式
//1. 在IDEA项目中创建对应的一个灯泡类(Buble) :灯泡类中没有属性,只有一个发光的方法light();根据不同的灯泡显示不同的颜色。
abstract class Buble {
abstract void light();
}
//2. 设计一个红灯泡(RedBuble)类:他满足了灯泡类的要求,并根据灯泡的颜色重写了发光的方法。
class RedBuble extends Buble{
@Override
void light() {
System.out.println("发红光……");
}
}
class GreenBuble extends Buble{
//3. 设计一个绿灯泡(GreenBuble)类:他满足了灯泡类的要求,并根据灯泡的颜色重写了发光的方法。
@Override
void light() {
System.out.println("发绿光……");
}
}
class Lamp{
//4. 设计台灯类(Lamp):该类含有一个成员变量灯泡(灯泡类型)。对成员变量进行封装。
private Buble buble;
//5. 声明一个没有参数的构造方法,重载一个构造方法,用于为台灯的灯泡赋值;
public Lamp(){}
public Lamp(Buble buble){
this.buble = buble;
}
//6. 为私有的灯泡提供getter和setter方法,用于赋值和取值。
public void setBuble(Buble buble) {
this.buble = buble;
}
public Buble getBuble() {
return buble;
}
//7. 声明一个开灯(on)的方法,用于打开台灯后显示灯泡的颜色的功能
public void on(){
buble.light();
}
}
class Test{
//8. 创建一个测试类:计出一段代码可以使台灯开启灯泡发亮,并且保证替换不同种类的灯泡台灯类代码不被修改.
public static void main(String[] args) {
Buble red = new RedBuble();
Buble green = new GreenBuble();
Lamp lamp1 = new Lamp(red);
lamp1.on();
Lamp lamp2 = new Lamp(green);
lamp2.on();
}
}
3.墨盒和纸张的规格是一种约定 。打印机需要遵守这些约定。
用面向接口编程的方式开发,制定墨盒、纸张的约定或标准,打印机厂商使用墨盒、纸张的标准开发打印机,其他厂商按照墨盒、纸张的标准生产墨盒、纸张
//墨盒的接口
public interface InkBox {
//获取墨盒的颜色
String getColor();
}
//纸张的接口
interface Paper{
//获取纸张的大小
String getSize();
}
//墨盒类
class ColorInkBox implements InkBox{
@Override
public String getColor() {
return "彩色";
}
}
class HBInkBox implements InkBox{
@Override
public String getColor() {
return "黑白";
}
}
//纸张
class A4Paper implements Paper{
@Override
public String getSize() {
return "A4";
}
}
class B5Paper implements Paper{
@Override
public String getSize() {
return "B5";
}
}
//打印机
class DaYinJi{
//属性:
private InkBox inkBox;
private Paper paper;
//构造方法:
public DaYinJi(){}
public DaYinJi(InkBox inkBox,Paper paper){
this.inkBox=inkBox;
this.paper=paper;
}
//提供getter和setter方法
public void setInkBox(InkBox inkBox){
this.inkBox=inkBox;
}
public InkBox getInkBox(){
return inkBox;
}
public void setPaper(Paper paper){
this.paper=paper;
}
public Paper getPaper(){
return paper;
}
//打印机工作
public void display(){
System.out.println("使用"+inkBox.getColor()+"墨盒在"+paper.getSize()+"进行工作");
}
}
//创建测试类:
class TestDaYinJi{
public static void main(String[] args) {
//购买墨盒:多态
InkBox inkBox1=new ColorInkBox();
InkBox inkBox2=new HBInkBox();
//购买纸张:多态
Paper a4=new A4Paper();
Paper b5=new B5Paper();
//组装打印机
DaYinJi daYinJi=new DaYinJi(inkBox2,b5);
//打印:
daYinJi.display();
}
}
内部类:
在一个类中定义一个类。
举例:在一个类A的内部定义一个类B, 类B就被称为内部类
内部类的声明语法:
[public] class 外部类名{
[public] class 内部类{
}
}
内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建对象
案例:
//外部类
public class Outter {
//属性:
private String name="张三";
//内部类:
public class Inner{
//属性:
public int age=18;
//方法:
//内部类调用外部类可以直接访问
public void say(){
System.out.println("我是一个内部类!!!!我得外部类的名字是:"+name);
//调用外部类的方法:
display();
}
}
//方法:
public void display(){
//外部类调用内部类必须先创建对象
Inner in=new Inner();
System.out.println("我是一个外部类!!我得内部类的年龄是:"+in.age);
in.say();
}
}
内部类的使用语法:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
举例:Outer.Inner oi = new Outer().new Inner();
案例
//结合上面
class Test{
public static void main(String[] args) {
//创建外部类的对象
Outter out=new Outter();
//创建内部类的对象:
Outter.Inner in=new Outter().new Inner();
Outter.Inner in1=out.new Inner();
}
}
私有化的内部类:
将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。
//外部类1
class Outter1{
//私有化内部类:
private class Inner1{
//方法:
public void show(){
System.out.println("我是一个私有化的内部类!!!!");
}
}
//获取内部类的方法:
public void getInner(){
Inner1 in1=new Inner1();
in1.show();
}
}
class Test1{
public static void main(String[] args) {
//使用内部类:
Outter1 out=new Outter1();
out.getInner();
}
}
局部内部类:
局部内部类定义:
局部内部类是在方法中定义的类。(只能在方法内部使用)
局部内部类的访问方式:
局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,也可以访问方法内的局部变量
//外部类:
public class Outter2 {
//属性:全局变量
private String name="李四";
//方法:
public void method(){
//属性:局部变量
int age=18;
//局部内部类:
class Inner2{
//方法:
public void display(){
System.out.println("我是一个局部的内部类!!!外部类的名字是:"+name);
System.out.println("我的外部类的局部变量是:"+age);
}
}
//创建内部类的对象:
Inner2 in2=new Inner2();
in2.display();
}
}
匿名内部类:
存在一个类或者接口,这里的类可以是具体类也可以是抽象类 .
匿名内部类的格式:
new 类名 ( ) { 重写方法 } new 接口名 ( ) { 重写方法 }
匿名内部类的本质:
是一个继承了该类或者实现了该接口的子类匿名对象,匿名内部类可以通过多态的形式接受.
匿名内部类在创建完对象之后可以在对象的后面直接通过.方法名()直接调用方法
//动物类
public abstract class Animal {
//吃的方法:
public abstract void eat();
}
/*class Dog extends Animal{
@Override
public void eat() {
System.out.println("吃骨头!!!");
}
}*/
class Test2{
public static void main(String[] args) {
//创建对象:
//匿名内部类
new Animal(){
@Override
public void eat() {
System.out.println("吃骨头!!!!");
}
}.eat();
new Animal() {
@Override
public void eat() {
System.out.println("吃鱼!!!!!");
}
}.eat();
}
}
匿名内部类的案例练习:
定义一个接口Jumpping,该接口定义了跳高的方法。
如果我们的Cat类实现了此接口,则可以完成跳高动作,如果我们的Dog类实现了此接口,则也可以完成跳高动作。现有操作类JumppingOperator来完成动物的跳高操作。分别传递Cat对象或者Dog对象都可进行跳高。请分别使用多态和匿名内部类来实现设计操作。
public interface Jumpping1 {
//定义跳高的方法:
void jump();
}
//比赛类:
class JumppingOperator1 {
//跳高比赛:多态
public void operator(Jumpping j) {
j.jump();//跳高的方法
}
public static void main(String[] args) {
//创建比赛的对象
JumppingOperator1 o=new JumppingOperator1();
o.operator(new Jumpping(){
@Override
public void jump() {
System.out.println("狗可以跳高啦!!!!");
}
});
o.operator(new Jumpping() {
@Override
public void jump() {
System.out.println("猫可以跳高啦");
}
});
}
}
Lambda表达式(闭包):
Lambda 表达式,也可称为闭包, 它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑
Lambda简介:
Lambda 表达式是一个匿名函数。简单来说,这是一种没有声明的方法,即没有访问修饰符,返回值声明和名称。
Lambda表达式是一种函数式思想的体现,这种表达式只针对有一个抽象方法的接口实现.
Lambda表达式的语法:
语法:([参数列表])->{代码块;}
形式参数:
如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->
:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块
: 是我们具体要做的事情,也就是以前我们写的方法体内容
Lambda表达式的前提:
有一个接口;
接口中有且仅有一个抽象方法;
@FunctionalInterface
注解
:标注了函数式接口.代表接口里面只有一个函数
Lambda表达式的案例代码:
//接口:
@FunctionalInterface//注解:标注了函数式接口.代表接口里面只有一个函数
public interface Animal {
//吃的方法:
void eat();
}
//实现类:
class Dog implements Animal{
@Override
public void eat() {
System.out.println("这是多态的实现:");
System.out.println("一天一水果,疾病远离我!!!!");
}
}
//饲养员
class Feeder{
//喂:静态的
public static void feed(Animal animal){
animal.eat();
}
public static void main(String[] args) {
//模拟饲养喂动物
//多态:创建动物的对象
Animal dog=new Dog();
feed(dog);
//匿名内部类
feed(new Animal(){
@Override
public void eat() {
System.out.println("匿名内部类实现:");
System.out.println("一天一水果,疾病远离我!!!!");
}
});
//Lambda表达式:
feed(()->{
System.out.println("Lambda表达式实现:");
System.out.println("一天一水果,疾病远离我!!!!");
});
}
}
Lambda表达式的案例练习:
- 不需要参数,返回值为 5:() -> 5
//函数式接口
@FunctionalInterface
public interface Num {
//声明一个抽象方法:
int getNum();
}
//测试类:
class TestNum{
//声明使用接口的方法:
public static void useNum(Num num){
int value=num.getNum();
System.out.println("这是我获取到的值:"+value);
}
//主方法:
public static void main(String[] args) {
//匿名内部类:
useNum(new Num(){
@Override
public int getNum() {
return 5;
}
});
//Lambda表达式
useNum(()->{return 5;});
useNum(()->5);
}
}
2.接收一个参数(数字类型),返回其2倍的值 :(x) -> 2 * x
//函数式接口:
@FunctionalInterface
public interface Num2 {
//声明一个方法:
int getNum2(int num);
}
//测试类:
class TestNum2{
//声明使用函数式接口的方法
public static void useNum2(Num2 num2,int num){
int value = num2.getNum2(num);
System.out.println("我的参数值的2倍是:"+value);
}
//主方法:
public static void main(String[] args) {
//匿名内部类
useNum2(new Num2() {
@Override
public int getNum2(int num) {
return 2*num;
}
},8);//16
//Lambda表达式:
useNum2((aa)->{return 2*aa;},10);//20
useNum2((aa)->2*aa,10);
}
}
3.接受2个参数(数字),并返回他们的差值 :(x, y) -> x – y
//函数式接口
@FunctionalInterface
public interface Num3 {
int getNum3(int x,int y);
}
//测试类:
class TestNum3{
//声明一个使用的方法:
public static void useNum3(Num3 num3,int x,int y){
int value= num3.getNum3(x,y);
System.out.println("x-y="+value);
}
//主方法
public static void main(String[] args) {
//Lambda表达式:
useNum3((x,y)->{return x-y;},45,31);
useNum3((x,y)->x-y,45,31);
}
}
4.接受2个参数(数字),并返回他们的差值 :(x, y) -> x + y
//接受2个参数(数字),并返回他们的差值 :(x, y) -> x – y
@FunctionalInterface
public interface Num4 {
// 方法
int getNum4(int x,int y);
}
class TestNum4{
// 函数式接口的方法
public static void useNum4(Num4 num4,int x,int y){
int val = num4.getNum4(x,y);
System.out.println("我的参数值的x+y是"+val);
}
public static void main(String[] args) {
// 匿名内部类
useNum4(new Num4() {
@Override
public int getNum4(int x,int y) {
return x+y;
}
},5,2);
// lambda表达式
useNum4((num1,num2) -> {return num1+num2;},10,3);
useNum4((num1,num2) -> num1+num2,10,3);
}
}
5.接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
上课讲的:
//函数式接口:
@FunctionalInterface
public interface String {
void getStr(java.lang.String str);
}
//测试类:
class TestString{
//声明一个调用的方法:
public static void useString(String str, java.lang.String s){
str.getStr(s);
}
public static void main(java.lang.String[] args) {
//Lambda表达式:
useString((s)->{
System.out.println(s);
},"一天一水果,疾病远离我!!!!");
}
}
自己写的:
//函数式接口
@FunctionalInterface
public interface Str{
void getStr(String str);
}
class TestStr{
// 调用方法
public static void useStr(Str str,String s){
str.getStr(s);
}
public static void main(String[] args) {
// lambda表达式
useStr((s)->{
System.out.println(s);
},"一天一水果,疾病远离我");
}
}
Lambda表达式调用类里面的静态方法:
如果是静态方法,则是ClassName::methodName
。如 Object ::equals
@FunctionalInterface
public interface Num {
//获取参数值的方法:
int getNum(int num);
}
//创建类:
class Static{
//静态方法:获取任意数字的绝对值
public static int abs(int num){
if(num>0){
return num;
}else{
return -num;
}
}
}
//测试类:
class TestNum{
//声明一个方法:使用我们的函数式接口
public static void useNum(Num num,int n){
int value = num.getNum(n);
System.out.println("我的value是:"+value);
}
public static void main(String[] args) {
//使用lambda表达式来调用方法:
useNum((num)->Static.abs(num),-12);
//调用方法的简化写法:
useNum(Static::abs,-12);
}
}
Lambda表达式调用类里面的实例方法:
如果是实例方法,则是Instance::methodName
。如Object obj=new Object();obj::equals;
@FunctionalInterface
public interface Num {
//获取参数值的方法:
int getNum(int num);
}
//创建类:
class Static{
//实例方法:获取任意数字的绝对值
public int abs(int num){
if(num>0){
return num;
}else{
return -num;
}
}
}
//测试类:
class TestNum{
//声明一个方法:使用我们的函数式接口
public static void useNum(Num num,int n){
int value = num.getNum(n);
System.out.println("我的value是:"+value);
}
public static void main(String[] args) {
//使用lambda表达式来调用方法:
useNum((num)->new Static().abs(num),-12);
//调用方法的简化写法:
useNum(new Static()::abs,-12);
}
}
lambda表达式调用构造方法:
构造函数.则是ClassName::new
@FunctionalInterface
public interface String1 {
//获取Str的对象
Str getStr(String str);
}
class Str{
private String name;
public Str(){}
public Str(String str){
this.name=str;
}
//打印的方法
public void display(){
System.out.println("我得名字是:"+name);
}
}
//测试类:
class TestStr{
//声明一个使用接口的方法:
public static Str useStr(String1 string1,String str){
Str s=string1.getStr(str);
return s;
}
public static void main(String[] args) {
//调用使用接口的方法:
Str str1=useStr((str)->new Str(str),"张三");
//使用渐变写法创建对象
Str str2=useStr(Str::new,"李四");
str1.display();
str2.display();
}
}
异常:
异常是程序在编译或运行过程出现的例外,这些例外在有的可以避免有的却无法避免
异常的分类:
- Throwable(总异常):包含下面两种情况:
-
error(错误):程序运行的代码问题,无法通过编码处理,只能修改代码。 byte b=128;
-
exception(异常):程序运行过程中的列外情况,可以通过编码进行处理。(包含以下两种情况:)
-
编译期异常:编写代码的时候直接报错,不可避免,必须进行处理。处理完继续编写
- ParseException 解析异常
DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date="1998-12-15 12:13:14"; df.parse(date);
-
运行时异常:编写代码的时候没有报错,但是在运行的时候,控制面板会报错。需要手动捕获。
-
- 常见的运行时异常:
-
NullPointerException 空指针异常
//声明String对象: String name=null; System.out.println(name.hashCode());
-
ArithmeticException 算术异常
System.out.println(12/0);
-
ArrayIndexOutOfBoundsException数组下标越界异常
int [] aa=new int [5]; System.out.println(aa[5]);
-
ClassCastException类型转换异常
Object object=new Integer(10); String str=(String) object;
异常处理:
-
try、catch、finally关键字捕获异常:
try{ //可能会出现异常的代码 }catch(ParseException e){ //捕获执行的代码 }finally{ //不管是否发生异常都要执行的代码 }
-
异常的捕获
-
语法格式
try{
可能产生异常对象的语句块。
}catch(异常类型 引用名){
针对当前异常类型对象的处理语句块;
}
… (可以写多个catch)
finally{
无论是否发生异常都应该执行的语句块。
} -
注意事项
当捕获异常的结构中有多个catch分支时,切记小范围的异常类型放在大范围的异常类型上面
懒人的写法:
catch(Exception e){…} -
执行流程
try{
a;
b;可能产生异常的语句
c;
}catch(Exception e){
e;
}finally{
f;
}
当没有产生异常的时候,程序的执行流程时:a b c f
当产生异常时,程序执行流程是 a b e f -
-
throws关键字声明抛出异常:
(1)基本概念
在某些特殊的场合中,当产生异常后却无法直接处理的/不想处理时,此时就可以将异常转移给当前方法的调用着,这就叫异常的抛出。(2)语法格式
返回值类型 方法名称(形参列表) throws 异常类型{...............}
(3)方法重写的原则
a.要求方法名相同、参数列表相同、返回值类型也相同,从jdk1.5开始允许返回子类类型。
b.访问权限不能变小,可以相同或者变大。
c.不能抛出更大的异常注意:
子类中重写以后的方法可以选择抛出与父类一样的异常、更小的异常、不抛出异常,但是不能抛出更大的异常、不同的异常。 -
自定义异常
(1)自定义异常的由来
java官方库中虽然提供了大量的异常类,但不足以描述现实生活中所有的异常情况,当出现官方库中没有描述
的异常情况时候就需要程序员自定义异常类加以描述,使得异常信息更加具备针对性和可读性。(2)自定义异常的流程
a.自定义类继承Exception类或者Exception类的子类
b.提供两个版本的构造方法,一个是无参构造方法,另一个是字符串做参数的构造方法 -
异常对象的抛出
throw new 异常类型()
例如:
throw new Exception() -
throw和throws的区别?
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常 -
throws:异常的抛出,是处理异常的一种方式。
-
throw:创建异常,自定义异常的方法。
自定义异常:自己定义的报错情况
继承自Exception的自定义异常:编译期异常
继承自RuntimeException的自定义异常:运行时异常
public class BalanceException extends Exception {
//提供构造方法:
public BalanceException() {}
public BalanceException(String message) {
super(message);
}
}
class Account {
//属性:
private double balance;
//提供构造方法:
public Account() {
}
public Account(double balance) {
this.balance = balance;
}
//方法:
public void setBalance(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
//定义一个取款的方法:
public void whitdraw(double money) throws BalanceException {
if (money > balance) {
//发生异常
throw new BalanceException("余额不足!!!!");
} else {
balance -= money;
System.out.println("取款后的余额是:" + balance);
}
}
}
class Test {
public static void main(String[] args) throws BalanceException {
//创建对象
Account account = new Account(500);
try {
account.whitdraw(600);
}catch (BalanceException e){
account.setBalance(10000);
account.whitdraw(600);
}
}
}
自定义异常案例:
自定义一个学生类,属性有 姓名 年龄,如果用户在给学生年龄赋值时,年龄小于0抛出一个AgeLT0Exception,大于150 抛出一个AgeGT150Exception
//自定义异常
//运行时异常
public class AgeLT0Exception extends RuntimeException {
public AgeLT0Exception(){}
public AgeLT0Exception(String message){
super(message);
}
}
//编译期异常
class AgeGT150Exception extends Exception{
public AgeGT150Exception(){}
public AgeGT150Exception(String message){
super(message);
}
}
//学生类:
class Student{
//属性:
private String stuName;
private int age;
//方法:getter和setter方法:
public void setStuName(String stuName){
this.stuName=stuName;
}
public String getStuName(){
return stuName;
}
public int getAge(){
return age;
}
// 抛出异常
public void setAge(int age) throws AgeGT150Exception {
if(age < 0){
//报异常
throw new AgeLT0Exception("年龄小于0 !!!!");
}else if(age > 150){
//报异常
throw new AgeGT150Exception("年龄大于150!!!");
}else{
this.age=age;
}
}
}
//测试类:
class TestStu{
//抛出异常
public static void main(String[] args) throws AgeGT150Exception {
//创建学生类的对象:
Student stu=new Student();
stu.setAge(156);
}
}
集合
集合(collection)有时又称为容器,它是一个对象,能将具有相同性质的多个元素汇聚成一个整体,集合被用于存储、获取、操纵和传输聚合的数据.
JAVA集合框架图:
集合接口:
Collection接口:
-
int size():获取集合的长度.
-
boolean isEmpty():判断集合是否为空
-
boolean add(E element):给集合添加元素。
-
boolean remove(Object o):删除指定元素
-
Iterator iterator():返回在集合元素上进行迭代的迭代器
-
void clear():清空集合。
List集合接口:
- 特点:
- 有序的集合。
- 可以包含重复的数据.
- 常用方法:
E get(int index):根据我们的下标获取指定元素。
E remove(int index):移除指定下标的集合。 - 其他:
<泛型>:指定集合存放的数据类型.
list集合对象案例:
public class TestList {
public static void main(String[] args) {
//创建list集合对象:
List<String> list=new ArrayList<>();
//往集合中存放数据:
//size():获取集合的长度.
int length= list.size();
System.out.println("集合长度是:"+length);
//boolean isEmpty():判断集合是否为空
boolean bo=list.isEmpty();
System.out.println("集合是否为空:"+bo);
//boolean add(E element):给集合添加元素。
boolean bo1=list.add("张三");//0
list.add("张三");//1
list.add("张三2");//2
list.add("张三3");//3
list.add("张三4");//4
list.add("张三5");
System.out.println("添加元素:"+bo1);
System.out.println("集合长度是:"+list.size());
//集合的遍历:
//for循环遍历:
System.out.println("---for循环遍历---");
for(int i=0;i<list.size();i++){//声明一个变量代表下标
System.out.println(list.get(i));
}
//增强for循环:
for(String str:list){
System.out.println(str);
}
//迭代器遍历:
Iterator it= list.iterator();
while(it.hasNext()){![请添加图片描述](https://img-blog.csdnimg.cn/31f8553fe59f4492b999823393c00c85.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6L-36YCU44G9,size_20,color_FFFFFF,t_70,g_se,x_16)
System.out.println(it.next());
}
//Lambda表达式遍历:
list.forEach((obj)->{
System.out.println(obj);
});
}
}
集合接口:
Collection接口:
-
方法:
- int size():获取集合的长度.
- boolean isEmpty():判断集合是否为空
- boolean add(E element):给集合添加元素。
- boolean remove(Object o):删除指定元素
- Iterator iterator():返回在集合元素上进行迭代的迭代器
- void clear():清空集合
List集合:
-
特点:
-
有序的集合(有序体现在有下标进行标记,下标从0开始)
-
可以包含重复的数据.
-
-
常用方法:
- E get(int index):根据我们的下标获取指定元素。
- E remove(int index):移除指定下标的集合。
-
其他:
-
<泛型>:指定集合存放的数据类型. 只能是类型不能是基本数据类型,即基本数据类对应的类
-
(简答题)泛型集合和非泛型集合有什么区别?
一个是弱类型,一个是强类型。而弱类型是指无法在应用程序编译期间得到检查,如array对象,你可以往这个对象中添加数字和字符都没有问题。但是在遍历操作的时候可能会牵扯到数据类型的转换,在不同类型转换的时候可能会出现类型转换是的异常。而强类型则在编译期间进行检查,如list标明我们只能够在集合中存储string字符串类型,一旦添加其他类型的数据就会在编译期间出现错的提示。
非泛型合集属于弱类型集合而泛型集合属于强类型集合。
-
-
使用:
public class TestList { public static void main(String[] args) { //创建list集合对象: List<String> list=new ArrayList<>(); //往集合中存放数据: //size():获取集合的长度. int length= list.size(); System.out.println("集合长度是:"+length); //boolean isEmpty():判断集合是否为空 boolean bo=list.isEmpty(); System.out.println("集合是否为空:"+bo); //boolean add(E element):给集合添加元素。 boolean bo1=list.add("张三");//0 list.add("张三");//1 list.add("张三2");//2 list.add("张三3");//3 list.add("张三4");//4 list.add("张三5"); System.out.println("添加元素:"+bo1); System.out.println("集合长度是:"+list.size()); //集合的遍历: //for循环遍历: System.out.println("---for循环遍历---"); for(int i=0;i<list.size();i++){//声明一个变量代表下标 System.out.println(list.get(i)); } //增强for循环: //声明一个和变量同类型的变量进行存放集合中的数据 for(String str:list){ System.out.println(str); } //迭代器遍历: Iterator it= list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } //Lambda表达式遍历: list.forEach((obj)->{ System.out.println(obj); }); } }
Set集合
-
特点
- set集合不可以存放重复元素
- set集合都是没有顺序的集合
- 全部都是从collection继承过来的方法
-
方法
1. int size():获取集合的长度. 2. boolean isEmpty():判断集合是否为空 3. boolean add(E element):给集合添加元素 4. boolean remove(Object o):删除指定元素 5. Iterator<E> iterator():返回在集合元素上进行迭代的迭代器 6. void clear():清空集合。
-
使用
import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class SetTest { public static void main(String[] args) { //创建一个set集合的对象 Set<Integer> set = new HashSet<>(); //集合添加数据 System.out.println("添加数据1"+set.add(1)); System.out.println("添加数据2"+set.add(2)); System.out.println("添加数据3"+set.add(3)); System.out.println("添加数据1"+set.add(1)); //int size()获取集合的长度 System.out.println("集合的长度是:"+set.size());//3 //boolean isEmpty()集合是否为空 System.out.println("集合是否为空:"+set.isEmpty()); //集合的遍历 //for (集合的泛型 变量名:集合名){} for (Integer i:set){ System.out.println(i); } System.out.println("-------------------迭代器变量-----------------"); //通过指针获取数据 Iterator<Integer> iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("--------------------Lambda表达式遍历-------------------------"); //obj代表集合中的每一个元素 set.forEach((obj)->{ System.out.println(obj); }); } }
-
案例
获取重复的字符
import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Test1 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("请输入一句话");//你好,我是张三 //接受键盘输入 String str=sc.nextLine(); //把String类型的字符串,拆分成字符数组 char [] chars=str.toCharArray();//{你,好,......} //创建Set集合 Set<Character> characterSet=new HashSet<>(); //for循环遍历 for (char ch:chars){ if(!characterSet.add(ch)){ System.out.println(ch+"是重复出现的字母"); } } } }
Map集合
-
特点
- 是一个双类集合
- 是一个包含键值对的集合
- 是一个无序的集合
- 键是不可以重复的,值是可以重复的
-
方法
- V put(K key,V value) 将指定的值与映射中的指定键进行关联
- Set keySet
- V put(K key , V value):将指定的值与映射中的指定键进行关联
- int size() 返回此映射中键值映射关系的数量
- V get(Object key) 返回指定键所对应的映射值
-
使用
import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class MapTest { public static void main(String[] args) { Map<Integer,String> map = new HashMap<>(); map.put(1,"张三"); map.put(2,"李四"); map.put(3,"王五"); map.put(1,"田七"); //获取键值对的映射个数 System.out.println("集合的长度是:"+map.size()); System.out.println(1+"对应的值是:"+map.get(1)); System.out.println("集合是否为空:"+map.isEmpty()); // 将map的key都放到set集合中 // 将map集合转换成了set集合 Set<Integer> set = map.keySet(); // map集合的遍历 和set的遍历种类一样 for (Integer i:set){ System.out.println(i+"对应的值是:"+map.get(i)); } map.forEach((key,val)->{ System.out.println(key+"对应的值是"+val); }); } }
-
案例:
键盘输入一句话,统计每一个字符出现得次数
import java.util.HashSet; import java.util.Iterator; import java.util.Set; //键盘输入一句话,统计每一个字符出现得次数。 public class Test { public static void main(String[] args) { //键盘输入一句话,统计每一个字符出现得次数。 Scanner sc=new Scanner(System.in); System.out.println("请输入一句话:");//asdasdasd String str=sc.nextLine(); //{a,s,d,a,s,d,a,s,d} char [] chars=str.toCharArray(); //创建一个Map集合: Map<Character,Integer> map=new HashMap<>(); Set<Character> set=new HashSet<>(); //遍历char数组: for(char ch:chars){ //判断字符是否第一次出现 if(set.add(ch)){//这是第一次出现 map.put(ch,1); }else{//不是第一次出现 int num= map.get(ch); map.put(ch,num+1); } } //直接使用Lambda表达式遍历结合 map.forEach((key,value)->{ System.out.println(key+"出现了"+value+"次;"); }); } }
Collections 工具类
排序:
package collection;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
// 创建一个lsit集合
Integer [] arr = {13,21,2,35,25,66};
// 数组转换为集合
List<Integer> list = Arrays.asList(arr);
Collections.sort(list);
// 随机排序
// Collection.shuffle(list);
// 反转
// Collections.reverse(list);
// 二分查找法
int a;
a = Collections.binarySearch(list,25);
// 查找极值
int max = Collections.max(list);
int min = Collections.min(list);
// 集合遍历
// lambda表达式方法
list.forEach((obj)->{
System.out.print("-----"+obj);
});
System.out.println("\n-----------------------------------------------");
System.out.println("25的下标为"+a);
System.out.println("集合中的最大值"+max+",集合中的最小值"+min);
}
}
package collection;
import java.util.*;
public class Student {
private String name;
private String clazz;
private double score;
public Student(){}
public Student(String name,String clazz,double score){
this.name = name;
this.clazz = clazz;
this.score = score;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public void setScore(double score) {
this.score = score;
}
public String getClazz() {
return clazz;
}
public double getScore() {
return score;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
// 重写toString方法,在打印该对象时显示的格式
// 默认是一个该文件的路径加一个16进制的hashCode值
// @Override
// public String toString() {
// return "Student{" +
// "name='" + name + '\'' +
// ", clazz='" + clazz + '\'' +
// ", score=" + score +
// '}';
// }
// public static void main(String[] args) {
// Student student = new Student("张三","一班",23);
// System.out.println(student);
// }
}
class TestList{
public static void main(String[] args) {
// 创建一个学生对象
Student student = new Student("张三","2班",23);
Student student1 = new Student("张2","1班",83);
Student student2 = new Student("张4","4班",63);
Student student3 = new Student("张5","1班",63);
Student student4 = new Student("张6","3班",73);
Student student5 = new Student("张7","2班",79);
Student student6 = new Student("张8","3班",71);
Student []students = {student,student1,student2,student3,student4,student5,student6};
// 数组转换为集合
List<Student> list = Arrays.asList(students);
// 创建两个map结合,一个存放总分,一个存放人数
Map<String,Double> map = new HashMap<>();
Map<String,Integer> map2 = new HashMap<>();
// 创建一个set集合用于分班
Set<String> set = new HashSet<>();
// 对list集合进行遍历
list.forEach((stu)->{
// 对学生进行分班
if (set.add(stu.getClazz())){//这个学生是这个版的第一个人
map.put(stu.getClazz(),stu.getScore());
map2.put(stu.getClazz(),1);
}else {
// 这个班级已有其他人,获取本班的原有的总成绩
double sum = map.get(stu.getClazz());
int count = map2.get(stu.getClazz());
map.put(stu.getClazz(),sum+stu.getScore());
map2.put(stu.getClazz(),++count);
}
});
// 遍历map集合
map.forEach((key,val)->{
System.out.println(key+"班级的总分为"+val);
});
map2.forEach((key,val)->{
System.out.println(key+"班级的总人数为"+val);
});
// 技术平均成绩
set.forEach((obj)->{
double sum = map.get(obj);
int count = map2.get(obj);
System.out.println(obj+"的平均分为"+sum/count);
});
}
}