目录
1.面向对象的初步认识
1.1什么是面向对象
Java 是一门纯面向对象的语言 (Object Oriented Program ,简称 OOP) ,在面向对象的世界里,一切皆为对象。 面 向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情 。用面向对象的思想来涉及程序,更符合人 们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
1.2 面向对象与面向过程
面向过程编程:
public static void main(String[] args) {
int[] arr=new int[]{1,2,3,4,5,6,7,8,9,10};
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
if(i<arr.length-1){
System.out.print(", ");
}
}
System.out.println("]");
}
就如同上面的示例代码:面向过程编程需要完整地把每个步骤写出来以实现某种功能。
而对于面向对象编程来说:
public static void main(String[] args) {
int[] arr=new int[]{1,2,3,4,5,6,7,8,9,10};
System.out.println(Arrays.toString(arr));
}
例如上面这段代码,总共有两个对象:一个 是数组,一个是库函数toString
我只需要将数组传入toString函数中,它就会自动实现将数组转为字符串的功能
至于这个函数是如何实现的,我们作为使用者则不需要关注。
结论:在面向对象过程中,我只需要关注对象与对象之间的交互,并不需要知道它的功能是如何实现的
相较于面向过程,使用面向对象思想,我只需要调用库函数,仅一行代码就能实现相同的功能。
因此可以看出相较于面对过程编程,面对对象编程能够大幅提高写代码的效率。
2. 类定义和使用
2.1 简单认识类
比如:洗衣机,它是一个品牌,在 Java 中可以将其看成是一个类别。属性:产品品牌,型号,产品重量,外观尺寸,颜色 ...功能:洗衣,烘干、定时 ....
那么在Java语言中,如何对上述的洗衣机类来进行定义呢?
2.2 类的定义格式
在java中定义类时需要用到class关键字,具体语法如下 :
// 创建类class ClassName {fifield ; // 字段 ( 属性 ) 或者 成员变量method ; // 行为 或者 成员方法}
其中,class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的 成员属性 或者类 成员变量 。方法主要说明类具有哪些功能,称为类的 成员方法 。
class WashMachine {public String brand ; // 品牌public String type ; // 型号public double weight ; // 重量public double length ; // 长public double width ; // 宽public double height ; // 高public String color ; // 颜色public void washClothes (){ // 洗衣服System . out . println ( " 洗衣功能 " );}public void dryClothes (){ // 脱水System . out . println ( " 脱水功能 " );}public void setTime (){ // 定时System . out . println ( " 定时功能 " );}}
2.3 一些例子
2.3.1 定义一个狗类
class PetDog {public String name ; // 名字public String color ; // 颜色// 狗的属性public void barks () {System . out . println ( name + ": 旺旺旺 ~~~" );}// 狗的行为public void wag () {System . out . println ( name + ": 摇尾巴 ~~~" );}}
2.3.2 定义一个学生类
public class Student {public String name ;public String gender ;public short age ;public double score ;public void DoClass (){}public void DoHomework (){}public void Exam (){}}
右键类名->Refactor->Rename
单击Rename后会弹出这样一个窗口:
在框选出来的位置进行重命名,然后点Refactor按钮确认。
确认之后,文件名和类名会自动更改成新名字。
3. 类的实例化
3.1 什么是实例化
定义了一个类,就相当于在计算机中定义了一种新的类型 ,与 int , double 类似,只不过 int 和 double 是 java 语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:PetDog 类和 Student 类。它们都是类 ( 一种新定义的类型) 有了这些自定义的类型之后,就可以使用这些类来定义实例 ( 或者称为对象 ) 。用类类型创建对象的过程,称为类的实例化 ,在 java 中采用 new 关键字,配合类名来实例化对象。
例如:
class PetDog{
public String name;
public String color;
public void barks(){
System.out.println(name+":汪汪汪");
}
public void wag(){
System.out.println(name+":正在摇尾巴~");
}
}
public class Main {public static void main ( String [] args ) {PetDog dogh = new PetDog (); // 通过 new 实例化对象dogh . name = " 阿黄 " ;dogh . color = " 黑黄 " ;dogh . barks ();dogh . wag ();PetDog dogs = new PetDog (); // 通过 new 实例化对象dogs . name = " 阿黄 " ;dogs . color = " 黑黄 " ;dogs . barks ();dogs . wag ();}}
输出:
3.2 类和对象的说明
1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
2. 类是一种自定义的类型,可以用来定义变量.
3. 一个类可以实例化出多个对象, 实例化出的对象 占用实际的物理空间,存储类成员变量4. 做个比方。 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图 ,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
4. this引用
4.1 为什么要有this引用
先来看一个例子:
public class Date {public int year ;public int month ;public int day ;public void setDay ( int y , int m , int d ){year = y ;month = m ;day = d ;}public void printDate (){System . out . println ( year + "/" + month + "/" + day );}public static void main ( String [] args ) {// 构造三个日期类型的对象 d1 d2 d3Date d1 = new Date ();Date d2 = new Date ();Date d3 = new Date ();// 对 d1 , d2 , d3 的日期设置d1 . setDay ( 2020 , 9 , 15 );d2 . setDay ( 2020 , 9 , 16 );d3 . setDay ( 2020 , 9 , 17 );// 打印日期中的内容d1 . printDate ();d2 . printDate ();d3 . printDate ();}}
public void setDay ( int year , int month , int day ){year = year ;month = month ;day = day ;}
原因:局部变量的优先级大于成员变量。因此,在setDay方法中,实现的是局部变量=局部变量。并没有改变成员变量。所以打印成员变量的时候,成员变量为初始值0。
4.2 什么是this引用
this 引用指向当前对象 ( 成员方法运行时调用该成员方法的对象 ) , 在成员方法中所有成员变量的操作,都是通过该引用去访问 。只不过所有的操作对用户是透明的,即用户不需要来传递, 编译器自动完成 。
class Date {
public int year;
public int month;
public int day;
public void setDay(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date();
Date d2 = new Date();
Date d3 = new Date();
d1.setDay(2020,9,15);
d2.setDay(2020,9,16);
d3.setDay(2020,9,17);
d1.printDate();
d2.printDate();
d3.printDate();
}
更改代码:在所有成员变量前加一个 this. 看看结果会是如何?
注意:this引用的是调用成员方法的对象。
4.3 this引用的特性
1. this 的类型:对应类类型引用, 即哪个对象调用就是哪个对象的引用类型2. this 只能在 "成员方法" 中使用3. 在"成员方法"中,this只能引用当前对象,不能再引用其他对象4. this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收
对于第④点,我用如下代码来证明:
我在所有成员方法的第一个位置添加了参数:Date this
而添加了参数的代码并没有报任何错误。这说明了Date this参数是本来就存在的,只是被隐藏了。
5. 对象的构造及初始化
5.1 如何初始化对象
我们一般是怎么给对象初始化值的:
public static void main(String[] args) {
Date d = new Date();
d.printDate();
d.setDate(2021,6,9);
d.printDate();
}
5.2 构造方法
5.2.1 概念
构造方法:名字与类名相同, 没有返回值类型 ,设置为 void 也不行一般情况下使用 public 修饰在 创建对象时由编译器自动调用 ,并且在对象的生命周期内只调用一次
class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("Date(int,int,int)方法被调用了");
}
public void printDate(){
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
public class Test {
public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显式调用构造方法
Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
d.printDate(); // 2021-6-9
}
5.2.2 特性
class Date {
public int year;
public int month;
public int day; // 无参构造方法
public Date(){
this.year = 1900;
this.month = 1;
this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date();
d1.printDate();
Date d2= new Date(2024,5,18);
d2.printDate();
}
class Date {
public int year;
public int month;
public int day;
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date();
d1.printDate();
}
上述Date类中,没有定义任何构造方法,编译器会默认生成一个不带参数的构造方法。
class Date {
public int year;
public int month;
public int day;
//定义了一个带参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date();
d1.printDate();
}
编译器生成的构造函数必然是无参的,当我们实例化对象时调用无参的构造函数,编译器却报错了
这说明编译器并没有生成一个无参的构造函数,原因是我们已经在类中定义了一个构造函数了。
class Date {
public int year;
public int month;
public int day;
public Date(){
//此处在无参的构造函数中调用了带有三个参数的构造函数
this(1900,1,1);
}
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date();//调用无参构造函数
d1.printDate();
}
public Date (){this ( 1900 , 1 , 1 );}public Date ( int year , int month , int day ) {this ();}/*无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用编译报错: Error:(19, 12) java: 递归构造器调用*/
5.3 默认初始化
在上文中提出的第二个问题:为什么局部变量在使用时必须要初始化,而成员变量可以不用呢?
class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
//此处并没有给成员变量赋值,而是直接打印成员变量
System.out.print(year+" ");
System.out.print(month+" ");
System.out.print(day+" ");
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date(2024,5,18);
}
Date d = new Date ( 2021 , 6 , 9 );
即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
数据类型 | 默认值 |
byte | 0 |
char | '\u0000' |
short | 0 |
int | 0 |
long | 0L |
boolean | false |
float | 0.0f |
double | 0.0 |
reference | null |
6. 调用构造方法,给对象中各个成员赋值
5.4 就地初始化
在声明成员变量时,就直接给出了初始值。
class Date {
public int year=1900;
public int month=1;
public int day=1;
public Date(){
}
public Date(int year, int month, int day) {
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
}
public class Test {
public static void main(String[] args) {
Date d1 = new Date(2024,5,18);
d1.printDate();
Date d2=new Date();
d2.printDate();
}
注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中
6. 封装
6.1 封装的概念
6.2 访问限定符
6.3 封装扩展之包
6.3.1 包的概念
6.3.2 导入包中的类
public class Test {public static void main ( String [] args ) {java . util . Date date = new java . util . Date ();// 得到一个毫秒级别的时间戳System . out . println ( date . getTime ());}}
但是这种写法比较麻烦一些, 可以使用 import语句导入包.
import java.util.Date;public class Test {public static void main ( String [] args ) {Date date = new Date ();// 得到一个毫秒级别的时间戳System . out . println ( date . getTime ());}}
import java . util . * ;public class Test {public static void main ( String [] args ) {Date date = new Date ();// 得到一个毫秒级别的时间戳System . out . println ( date . getTime ());}}
import java . util . * ;import java . sql . * ;public class Test {public static void main ( String [] args ) {// util 和 sql 中都存在一个 Date 这样的类 , 此时就会出现歧义 , 编译出错Date date = new Date ();System . out . println ( date . getTime ());}}// 编译出错Error :( 5 , 9 ) java : 对 Date 的引用不明确java . sql 中的类 java . sql . Date 和 java . util 中的类 java . util . Date 都匹配
import java . util . * ;import java . sql . * ;public class Test {public static void main ( String [] args ) {java . util . Date date = new java . util . Date ();System . out . println ( date . getTime ());}}
import static java . lang . Math . * ;public class Test {public static void main ( String [] args ) {double x = 30 ;double y = 40 ;// 静态导入的方式写起来更方便一些 .// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));double result = sqrt ( pow ( x , 2 ) + pow ( y , 2 ));System . out . println ( result );}}
6.3.3 自定义包
2. 在弹出的对话框中输入包名, 例如 com.xxx.demo1
6.3.4 常见的包
7. static成员
7.1 再谈学生类
这是一个学生类(在 2.3.2 处初次定义):
public class Student{
public String name;
public String gender;
public short age;
public double score;
public void DoClass(){}
public void DoHomework(){}
public void Exam(){}
public Student(String name, String gender, int age, double score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
}
public static void main(String[] args) {
Student s1 = new Student("Li leilei", "男", 18, 3.8);
Student s2 = new Student("Han MeiMei", "女", 19, 4.0);
Student s3 = new Student("Jim", "男", 18, 2.6);
}
}
7.2 static修饰成员变量
static 修饰的成员变量,称为静态成员变量 ,静态成员变量最大的特性: 不属于某个具体的对象,是所有对象所共 享的 。
public class Student {
public String name;
public String gender;
public int age;
public double score;
public static String classRoom = "Bit306";
public Student(String name, String gender, int age, double score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
}
public static void main(String[] args) {
Student s1 = new Student("Li leilei", "男", 18, 3.8);
Student s2 = new Student("Han MeiMei", "女", 19, 4.0);
Student s3 = new Student("Jim", "男", 18, 2.6);
System.out.println(s1.classRoom);
System.out.println(s2.classRoom);
System.out.println(s3.classRoom);
}
}
调试上述代码,然后在监视窗口中可以看到,静态成员变量并没有存储到某个具体的对象中。
7.3 static修饰成员方法
public class Student {private String name ;private String gender ;private int age ;private double score ;private static String classRoom = "Bit306" ;// ...}Public class TestStudent {public static void main ( String [] args ) {System . out . println ( Student . classRoom );}}编译失败:Error :( 10 , 35 ) java : classRoom 在 extend01 . Student 中是 private 访问控制
public class Student {// ...private static String classRoom = "Bit306" ;// ...public static String getClassRoom (){return classRoom ;}}public class TestStudent {public static void main ( String [] args ) {System . out . println ( Student . getClassRoom ());}}输出:Bit306
public static String getClassRoom (){System . out . println ( this );return classRoom ;}// 编译失败: Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 thispublic static String getClassRoom (){age += 1 ;return classRoom ;}// 编译失败: Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 age
4. 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
public static String getClassRoom (){doClass ();return classRoom ;}// 编译报错: Error:(35, 9) java: 无法从静态上下文中引用非静态 方法 doClass()
7.4 static成员变量初始化
public class Student {private String name ;private String gender ;private int age ;private double score ;private static String classRoom = "Bit306" ; //定义时直接给出初始值// ...}
8. 代码块
8.1 代码块概念以及分类
8.2 普通代码块
普通代码块:定义在方法中的代码块
例如:
public class Main {public static void main ( String [] args ) {{ // 直接使用 {} 定义,普通方法块int x = 10 ;System . out . println ( "x1 = " + x );}int x = 100 ;System . out . println ( "x2 = " + x );}}// 执行结果x1 = 10x2 = 100
观察代码和结果可以看出:普通代码块有规划局部变量作用域的用处功能。
而且这种用法比较少见。
8.3 构造代码块
构造块:
定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
public class Student {
public String name;
public String gender;
private int age;
private double score;
public Student(){
System.out.println("构造函数");
}
{
this.name="bit";
this.gender="male";
this.age=18;
this.score=100.0;
System.out.println("实例代码块");
}
public void show(){
System.out.println(name+" "+gender+" "+age+" "+score);
}
public static void main(String[] args) {
Student stu1=new Student();
stu1.show();
//Student stu2=new Student();
}
}
类似于构造函数,每次创建新对象时都会调用一次实例代码块。
8.4 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
public class Student {
private String name;
private String gender;
private int age;
private double score;
private static String classRoom;
public Student(){
System.out.println("构造函数");
}
{
this.name="bit";
this.gender="male";
this.age=18;
this.score=100.0;
System.out.println("实例代码块");
}
static{
classRoom="Room306";
System.out.println("静态代码块");
}
public void show(){
System.out.println(name+" "+gender+" "+age+" "+score+" "+classRoom);
}
public static void main(String[] args) {
Student stu1=new Student();
stu1.show();
//Student stu2=new Student();
}
}
9. 内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中, 可以将一个类定义在另一个类或者一个方法的内部, 前者称为内部类,后者称为外部类 。内部类也是封装的一种体现。
例如:
public class OutClass {class InnerClass {}}// OutClass 是外部类// InnerClass 是内部类
9.1 内部类的分类
内部类分为四种:
成员内部类:①静态内部类 ②实例内部类
③局部内部类
④匿名内部类
9.2 成员内部类
在外部类中,内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类。
9.2.1 静态内部类
静态内部类: 即被static修饰的内部类
静态内部类要怎么定义?要如何使用?让我们直接看下面这个例子...
public class OutClass {
public int data1;
private int data2;
//静态内部类 被static修饰
static class InnerClass{
public int data3;
private int data4;
public void func(){
System.out.println("hahaha");
}
}
public static void main(String[] args) {
InnerClass innerClass=new InnerClass();//静态内部类对象的创建
innerClass.func();//静态内部类的成员访问
}
}
运行结果:
9.2.2 实例内部类
通过类比静态内部类,可以知道:实例内部类其实就是未被static修饰的内部类。
public class OutClass {
public int data1=1;
public static int data2=2;
//实例内部类
class InnerClass{
public int data3=3;
private int data4=4;
public void func(){
System.out.println("hahaha");
}
}
public static void main(String[] args) {
// 要访问实例内部类中成员,必须要创建实例内部类的对象
// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
//写法 1:直接创建实例内部类对象
OutClass.InnerClass innerClass1=new OutClass().new InnerClass();
innerClass1.func();//访问实例内部类成员
System.out.println("==============");//分隔符
//写法 2:先创建外部类对象 再创建实例内部类对象
OutClass outClass=new OutClass();
OutClass.InnerClass innerClass2= outClass.new InnerClass();
innerClass2.func();//访问实例内部类成员
}
}
9.3 局部内部类
局部内部类:定义在方法体内部的类就叫做局部内部类。
public class OutClass {
int a=10;
public void func(){
int b=20;
// 局部内部类:定义在方法体内部
//局部内部类不能被static public等关键字修饰
class InnerClass{
public void funcInnerClass(){
System.out.println(a);
System.out.println(b);
}
}
// 只能在该方法体内部使用,其他位置都不能用
InnerClass innerClass=new InnerClass();
innerClass.funcInnerClass();
}
public static void main(String[] args) {
OutClass outClass=new OutClass();
outClass.func();
}
}
9.4 匿名内部类
假设有一个类
public class OutClass {
public void func(){
System.out.println("hahaha");
}
}
那么 new OutClass(); 就是一个匿名对象
如果在后面加上一个花括号{} 就变成了匿名内部类,即:new OutClass(){ };
下面是一个简单的匿名内部类例子:
public class OutClass {
public void func(){
System.out.println("hahaha");
}
public static void main(String[] args) {
new OutClass(){
}.func();
}
}
运行结果:
如果在匿名对象内重写外部类方法,就会发生动态绑定。
public class OutClass {
public void func(){
System.out.println("hahaha");
}
public static void main(String[] args) {
new OutClass(){
@Override
public void func() {
System.out.println("heiheihei");
}
}.func();
}
}
10. 对象的打印
当我们每次需要打印对象的成员变量时,都要调用类函数来实现。
那么有没有更简便的方法呢,比如使用println来打印?不妨试试:
public class Person {String name ;String gender ;int age ;public Person ( String name , String gender , int age ) {this . name = name ;this . gender = gender ;this . age = age ;}public static void main ( String [] args ) {Person person = new Person ( "Jim" , " 男 " , 18 );System . out . println ( person );}}打印结果:
可以看到,打印出来的并不是类里面的成员变量。
如果想要默认打印对象中的属性该如何处理呢?答案:重写toString方法即可。
public class Person {String name ;String gender ;int age ;public Person ( String name , String gender , int age ) {this . name = name ;this . gender = gender ;this . age = age ;}@Overridepublic String toString () {return "[" + name + "," + gender + "," + age + "]" ;}public static void main ( String [] args ) {Person person = new Person ( "Jim" , " 男 " , 18 );System . out . println ( person );}}// 输出结果:
当我们在类里面重写了一个toString函数之后,使用println打印类就变成了打印其成员变量。
这是什么原因呢?
这是因为:不重写toString,当我们使用toString方法时,系统会调用默认的toString方法。
如果我们在类里面重写了一个toString方法,那么系统则会自动调用重写的toString方法
完
看完了觉得有用的姥爷们求求您们点个免费的赞和关注,这对我真的很重要!非常感谢大家!