Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下, 使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面 向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算 机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去 操作实现。
举例
洗衣服:
面向过程:把衣服脱下来—>找一个盆—>放点洗衣粉—>加点水—>浸泡10分钟—>揉一揉—>清洗衣服—>拧干—>晾 起来
面向对象:把衣服脱下来—>打开全自动洗衣机—>扔衣服—>按钮—>晾起来
区别:面向过程:强调步骤。
面向对象:强调对象,
特点 : 这里的对象就是洗衣机。 特点面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。 面向对象的语言中,包含了三大基本特征,即封装、继承和多态。
什么是类
现实中, 描述一类事物
什么是对象
类与对象的关系
类的定义
类的定义格式 :
成员变量 : 对应事物的属性
成员方法 : 对应事物的行为
public class ClassName{
// 成员变量
// 成员方法
}
定义类 : 就是定义类的成员, 包括成员变量和成员方法
成员变量 : 和以前定义变量集合是一样的; 只不过位置发生了改变,在类中,在方法外
成员方法 :和以前定义方法几乎是一样的, 只不过把static去掉
public class Student {
//成员变量
String name;//姓名
int age;//年龄
/*成员方法*/
//学习的方法
public void study() {
System.out.println("好好学习,天天向上");
}
//吃饭的方法
public void eat() {
System.out.println("学习饿了要吃饭");
}
}
类的创建及使用
通常情况下, 一个类并不能直接使用, 需要根据类创建一个对象, 才能使用
/*
1.导包
import 包名称.类名称
对于和当前类同属于一个包的情况, 可以省略包语句不写
2.创建,格式
类名称 对象名 = new 类名称()
Student stu = new Student()
3.使用
使用成员变量 : 对象名.成员变量名
使用成员方法 : 对象名.成员方法名(参数)
*/
成员变量如果没有赋值, 将会拥有一个默认值
一个对象的内存图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aSyhKq2X-1589014687148)(assets/1588925567220.png)] 两个对象使用同一个方法的内存图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VX1G8Bok-1589014687150)(assets/1588925972674.png)]
两个引用指向同一个对象的内存图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pV02KHlg-1589014687152)(assets/1588926293692.png)]
两个对象名称 指向了 同一个对象
使用对象作为方法的参数
当一个对象作为参数时, 传递到方法当中时, 实际上传递进去的是对象的地址值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZKjWl5KY-1589014687156)(assets/1588927036193.png)]
使用对象作为方法的返回值
当使用一个对象类型作为方法的返回值时, 返回值其实就是对象的地址值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1f1M6t8S-1589014687158)(assets/1588927806593.png)]
成员变量和局部变量的区别
局部变量 | 成员变量 | |
---|---|---|
定义的位置不一样 | 在方法的内部 | 在方法的外部,直接写在类当中 |
作用范围不一样 | 只有在方法当中使用, 出了方法就不能使用 | 整个类全都可以通用 |
默认值不一样 | 没有默认值, 如果要想使用,必须手动进行赋值 | 如果没有赋值, 会有默认值; 规则与数组一样 |
在内存当中的位置不同 | 栈内存 | 堆内存 |
生命周期不同 | 随着方法的调用而存在,随着方法的调用完毕而消失 | 随着对象的创建而存在,随着对象的消失而消失 |
定义 : 就是将一些细节信息隐藏起来, 对于外界不可见; 若需要访问某个属性, 提供公共方法对其访问; 适当的封装可以让代码更容易理解与维护, 也加强了代码的安全性
private 关键字将需要保护的成员变量和成员方法进行修饰; 在本类当中仍然可以随意访问; 超出了本类范围之外就不能再直接访问
private 数据类型 变量名 // private 返回值类型 方法名
public class Student{
private String name;
private int age;
}
对需要访问的成员变量, 提供对应的一对 getXxx, setXxx方法进行访问, 并且可以在set方法内部对属性进行校验
public class Student{
// 成员变量
private String name;
private int age;
private boolean male // 是不是爷们儿
// 对应每个属性的setXxx, getXxx方法
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int a){
age = a;
}
public int getAge(){
return age;
}
public void setMale(boolean b){
male = b;
}
public boolean isMale(){
return male
}
}
基本类型当中的 boolean值, 其的get方法 ,要写成 isXxx的形式
this代表所在类的当前对象的引用(地址值), 即对象自己的引用
通过谁调用的方法, this指代的 就是谁
当类的成员变量与方法的局部变量重名的时候, 会造成误解; 只能优先使用局部变量; 而this关键字后面的 . 一定是类的成员变量
构造方法是专门用来创建对象的方法, 当我们通过关键字new来创建对象时, 其实就是在调用构造方法
构造方法没有返回值, 所以不需要返回值类型, 甚至不需要void
注意事项 :
// 格式
public 类名称(参数类型 参数名称){
方法体
}
public class Student{
private String name;
private int age;
// 无参数构造方法
public Student() {}
// 有参数构造方法
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
定义一个标准的类
一个标准的类通常要拥有下面四个组成部分
这样标准的类也叫做 Java Bean; 快捷键自动生成Getter/Setter方法
Alt+Insert
或者 code -->Generate --> Constructor构造器 // Getter/Setter
定义 : 只有右边的对象, 没有左边的名字和赋值运算符
格式 : new 类名称();
注意事项 : 匿名对象只能使用唯一的一次, 下次再用不得不创建一个新对象
用途 : 有些情况下, 有的对象只能使用一次; 推荐使用匿名对象
定义 : 一个可以解析基本类型和字符串的简单文本扫描器
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
备注 : System.in 系统输入指的是通过键盘录入数据
使用import关键字导包, 在类的所有代码之前导包, 引入要使用的类型, java.lang包下的所有类无序导入 import 包名.类名;
import java.util.Scanner;
/*
Scanner : 实现键盘输入数据到程序当中
*/
public class Demo01Scanner {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 获取键盘输入的int数字
int num = sc.nextInt();
System.out.println("输入的int数字是: "+ num);
// 获取键盘输入的字符串
String str = sc.next();
System.out.println("输入的字符串是: "+ str);
}
}
详细Scanner类的操作 : 参考文档
用途 : 用来生产随机的数字
Random r = new Random();
int num = r.nextInt() // nextInt()无参数, 范围是int的范围
int num = r.nextInt(3) // 左闭右开 [)
练习 : 随机生成一个1-100之间的int数字, 键盘输入猜在多少次之内猜到
/*
用来生成随机数
*/
public class Demo01Random {
public static void main(String[] args) {
Random r = new Random();
int randomNum = r.nextInt(100)+1; // 生成[1,100]之间的数字
Scanner sc = new Scanner(System.in);
int number = 0;
while (true){
System.out.println("请输入你猜测的数字: ");
int guessNum = sc.nextInt(); // 键盘猜测输入的数字
if(guessNum>randomNum){
System.out.println("太大了, 请重试");
number += 1;
}else if(guessNum<randomNum){
System.out.println("太小了,请重试: ");
number += 1;
} else {
System.out.println("恭喜你,猜中啦");
break; // 不猜了
}
}
System.out.println("游戏结束, 猜了" + number + "次");
}
}
java.util.ArrayList
是大小可变的数组的实现, 存储在内的数据成为元素, 此类提供一些方法来操作内部存储的元素, ArrayList
中可不断添加元素, 其大小也自动增长
对于ArrayList来说, 有一个尖括号
泛型 : 也就是装在集合当中的所有元素, 全都是统一的什么类型
注意 : 泛型只能是引用类型, 不能是基本类型
// 创建格式
ArrayList list = new ArrayList<>();
注意事项 : 对于ArrayList来说, 直接打印得到的不是地址值, 而是内容; 如果内容为空, 得到的是 []
ArrayList的常用方法
for(int i=0, i
ArrayList集合存储基本数据类型
如果希望向集合ArrayList当中存储基本你数据类型, 必须使用基本数据类型对应的 “包装类”
基本类型 与 包装类有对应的关系, 除了int --> Integer, char --> Character特殊; 包装类都不用导入
练习 : 生成6个1-33之间的随机整数, 添加到集合,并遍历集合
/*
1. 需要存储6个数字, 创建一个集合,
2.产生随机数, 需要用到Random
3.用循环6次,来产生6个随机数字, for循环
4.循环内调用r.nextInt(33)+1,
5.把数字添加到集合中 :add
6.遍历集合 : for,size,get
*/
public Class ArrayList{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>();
Random random = new Random()
for(int i=0,i<=6,i++){
int num = random.nextInt(33)+1;
list.add(num);
}
// 遍历集合
for(int i=0,i<=list.size(),i++){
System.out.println(list.get(i))
}
}
}
练习2 : 存储自定义对象, 添加到结合,并遍历
public class TestArrayList{
public static void main(String[] args){
// 创建集合对象
ArrayList<Student> list = new ArrayList<Student>();
// 创建学生对象
Student s1 = new Student("赵丽颖",15);
Student s2 = new Student("唐嫣",19);
Student s3 = new Student("景甜",20);
Student s4 = new Student("柳岩",25);
// 把学生对象作为元素添加到集合中
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
// 遍历集合
for(int i=0;i<list.size();i++ ){
Student s = list.get(i);
System.out.println(s.getName()+"====="s.getAge());
}
}
}
java.lang.String 类代表字符串。Java程序中所有的字符串文字(例如 “abc” )都可以被看作是实现此类的实例。
字符串不变 : 字符串的值在创建后不能被更改
字符串常量池 : 程序当中直接写上的双引号字符串, 就在字符串常量池中
对于基本类型来说, == 是进行数值的比较
对于引用类型来说, == 是进行地址值的比较
ring s1 = "abc";
s1 += "d";
System.out.println(s1);
// "abcd
// 内存中有"abc","abcd"两个对象,s1从指向"abc",改变指向,指向了"abcd"
String对象是不可变的, 所以他们可以被共享
String s1 = "abc";
String s2 = "abc";
// 内存中只有一个"abc"对象被创建,同时被s1和s2共享。
“abc” 等效于 char[] data={ ‘a’ , ‘b’ , ‘c’ } 。
例如:
String str = "abc";
相当于:
char data[] = {'a', 'b', 'c'};
String str = new String(data)
// String底层是靠字符数组实现的。
列
// 无参构造
String str = new String()
// 通过字符数组构造
char chars[] = {'a', 'b', 'c'};
String str2 = new String(chars)
// 通过字节数组构造
byte bytes[] = { 97, 98, 99 };
String str3 = new String(bytes);
比较
public boolean equals (Object anObject) :将此字符串与指定对象进行比较。(比较数据值)
public boolean equalsIgnoreCase (String anotherString) :将此字符串与指定对象进行比较,忽略大小写。
获取与截取
public int length () :返回此字符串的长度。
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的单个字符
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。若不存在,则返回-1值
public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。
public class Demo02StringGet {
public static void main(String[] args) {
// 获取字符串的长度
int i = "nsfksbkfnafa".length();
System.out.println("字符串的长度为 : "+ i);
// 拼接字符串
String str1 = "Hello";
String str2 = "World";
String str3 = str1.concat(str2);
System.out.println("新的字符串为 : "+ str3);
// 获取指定位置的字符
System.out.println("指定位置的字符为: "+ str1.charAt(1));
// 获取参数字符串在字符串当中首次出现的位置
System.out.println("位置是 : "+ str1.indexOf("l"));
// 获取起始位置指定索引的子字符串
System.out.println("位置是 : "+ str1.substring(2)); // llo
// 获取起始位置和结束位置的指定索引的子字符串
System.out.println("位置是 : "+ str1.substring(2,3)); // l [)
}
}
转换
public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换。
/*
public char[] tocharArray() : 将当前字符串拆分成字符数组作为返回值
public byte[] getBytes() : 获取当前字符串底层的字节数据
public String replace(旧字符串,新字符串) :在原有字符串当中,使用新的字符串替换旧的字符串
*/
public class Demo02StringConvert {
public static void main(String[] args) {
char[] chars = "Hello".toCharArray();
// 转换为字符数组
for (int i = 0; i < chars.length; i++) {
System.out.println("每个字符分别为"+chars[i]);
}
// 转换为字节数组
byte[] bytes = "abc".getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}
// 替换旧的字符串当中的内容
String str = "it cast it Hello";
String newString = str.replace("it","IT");
System.out.println("新的字符串为: "+newString);
}
}
分割
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
注意事项 : split()的参数其实是一个正则表达式; 写两个 \ \ 代表转义
public class String_Demo03 {
public static void main(String[] args) {
//创建字符串对象
String s = "aa|bb|cc";
String[] strArray = s.split("|");
// ["aa","bb","cc"]
for(int x = 0; x < strArray.length; x++) {
System.out.println(strArray[x]); // aa bb cc
}
}
}
起因 : 对于某些成员变量来说, 是类的每个具体对象的共享变量, 那么这样的成员变量变不再属于对象自己,而属于类 , 用 static 修饰, 变成 类变量
定义 : 它可以用来修饰成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。
对于本类当中的静态方法, 可以省略类名称不写
静态是不能直接访问非静态; 因为在内存当中先有的静态内容, 后有的非静态内容; 即先编译静态变量和方法, 后编译非静态变量和方法
// 定义
static 数据类型 变量名;
static int age;
// 访问类变量(静态变量)
类名.静态变量名
// 调用静态方法
类名.静态方法名(参数)
static修饰类成员变量
public class Student {
private int id;
private String name;
private int age;
static String room;
private static int idCounter;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public static void main(String[] args) {
// main()
}
public Student(String name, int age) {
this.name = name;
this.age = age;
this.id = idCounter++;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cn.itcast.day08;
/*
如果一个成员变量, 使用了static来修饰, 则这个成员变量不属于对象自己, 供类的所有对象享用
*/
public class Demo03StaticField {
public static void main(String[] args) {
Student one = new Student("黄蓉",19);
Student two = new Student("郭靖",22);
one.room = "101教室";
System.out.println("姓名 : "+one.getName()+",年龄: "+one.getAge()+"教室: "+one.room+",学号 :"+one.getId());
System.out.println("姓名 : "+two.getName()+",年龄: "+two.getAge()+"教室: "+two.room+",学号 :"+two.getId());
}
}
static修饰类成员方法
被static修饰的成员方法, 可以直接被 类调用
static的内存图
根据类名称访问的静态成员变量的时候,全程和对象没得关系, 只和 类 有关系
根据类名称访问的静态成员的方法, 会在方法区当中单独开辟一块内存空间存储叫做静态区
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V6SSUp4t-1589014687160)(assets/1588996242827.png)]
静态代码块
写在类当中, 用 static {} 表示; 当第一次用到本类时, 静态代码块执行唯一的一次
静态内容总是优先于非静态, 所以静态代码块比构造方法先执行
用途 : 用来一次性地对静态成员变量进行赋值
java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等。其所有方法均为静态方法,调用起来非常简单。
public static String toString(int[] a) :返回参数数组的内容以字符串表示形式。
public static void main(String[] args) {
// 定义int 数组
int[] arr = {2,34,35,4,657,8,69,9};
// 打印数组,输出地址值
System.out.println(arr); // [I@2ac1fdc4//
// 数组内容转为字符串
String s = Arrays.toString(arr);
// 打印字符串,输出内容
System.out.println(s); // [2, 34, 35, 4, 657, 8, 69, 9]}
}
public static void sort(int[] a) :对指定的 int 型数组按数字升序(默认)进行排序。
public static void main(String[] args) {
// 定义int 数组
int[] arr = {24, 7, 5, 48, 4, 46, 35, 11, 6, 2};
System.out.println("排序前:"+ Arrays.toString(arr)); // 排序前:[24, 7, 5, 48, 4, 46, 35, 11, 6,2]
// 升序排序
Arrays.sort(arr);
System.out.println("排序后:"+ Arrays.toString(arr));// 排序后:[2, 4, 5, 6, 7, 11, 24, 35, 46,48]}
}
java.lang.Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具类,其所有方法均为静态方法,并且不会创建对象,调用起来非常简单。
public static double abs (double a) : 返回double 值的绝对值
double d1 = Math.abs(‐5); //d1的值为5
double d2 = Math.abs(5); //d2的值为5
public static double ceil(double a) : 返回大于等于参数的最小整数(向上取)
double d1 = Math.ceil(3.3); //d1的值为 4.0
double d2 = Math.ceil(‐3.3); //d2的值为 ‐3.0
double d3 = Math.ceil(5.1); //d3的值为 6.0
public static double floor(double a) : 返回小于等于参数的最大整数(向下取)
double d1 = Math.floor(3.3); //d1的值为3.0
double d2 = Math.floor(‐3.3); //d2的值为‐4.0
double d3 = Math.floor(5.1); //d3的值为 5.0
public static long round(double a) : 返回最接近参数的long(相当于四舍五入)
long d1 = Math.round(5.5); //d1的值为6.0
long d2 = Math.round(5.4); //d2的值为5.0
Java语言是单继承的, 一个类的直接父类只能有唯一的一个
继承是多态的前提, 如果没得继承, 就没有多态
继承的主要解决问题就是 : 共性抽取
通过 extends 关键字, 可以声明一个子类继承另外一个父类, 定义格式如下
class 父类 {..}
clas 子类 extends 父类 {...}
继承中访问成员变量的特点
在父子类的继承关系中, 成员变量的查找顺序 : 先在子类对象当中寻找, 找到则停止, 找不到在父类当中查找, 再往上找不到则报错
继承中访问成员方法的特点
在父子类的继承关系中, 成员方法的查找顺序 : 通过谁创建的对象, 就在谁当中去查找, 一直向上找到为止;不会向下去找子类的成员方法
继承中访问构造方法的特点
方法的复写
在继承关系当中, 方法的名称一样, 参数列表也一样, 只是内部的具体实现不同
重写时, 针对父类已经实现的方法, 必须先 super.父类方法(), 再重写
注意事项 :
拓展提示 : public > protected > (default 留空) > private
super关键字的三种用法
this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的
this关键字的三种方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fiSG8445-1589014687161)(assets/1589008206002.png)]
比如定义一个Animal, 里面有成员方法 eat() ,但是具体的吃什么我吗不知道, 浴室里面不能写内容; 这样的方法就是抽象方法, 抽象类与抽象方法都是用关键字 abstract 修饰
定义 : 父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明没有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。
抽象方法 :没有方法体即没有了 {} 的方法;
抽象类 : 包含抽象方法的类
public abstract class 类名 {
代码块;
public abstract void run();
}
抽象的使用
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。
假设创建了抽象类的对象, 调用抽象的方法, 而抽象方法没有方法体, 没有意义
子类的构造方法中, 有默认的super(), 需要访问父类的构造方法
未包含抽象方法的抽象类, 目的就是不想让调用者创建该类对象, 通常用于某些特殊的类结构设计
访问本类的另一个构造方法
4. super和this两种构造调头, 不能同时使用
[外链图片转存中…(img-fiSG8445-1589014687161)]
比如定义一个Animal, 里面有成员方法 eat() ,但是具体的吃什么我吗不知道, 浴室里面不能写内容; 这样的方法就是抽象方法, 抽象类与抽象方法都是用关键字 abstract 修饰
定义 : 父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明没有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。
抽象方法 :没有方法体即没有了 {} 的方法;
抽象类 : 包含抽象方法的类
public abstract class 类名 {
代码块;
public abstract void run();
}
抽象的使用
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。
假设创建了抽象类的对象, 调用抽象的方法, 而抽象方法没有方法体, 没有意义
子类的构造方法中, 有默认的super(), 需要访问父类的构造方法
未包含抽象方法的抽象类, 目的就是不想让调用者创建该类对象, 通常用于某些特殊的类结构设计
假设不写所有抽象方法, 则类中可能包含抽象方法, 那么创建对象后, 调用抽象的方法, 没有意义