文章目录
- 面向对象快速入门
- 啥是对象?深入理解对象
- 对象在计算机中是啥?
- 面向对象编程是啥?
- 类的基本语法
- 构造器
- this
- 封装
- Javabean
- static关键字
- static修饰成员变量
- 如何访问静态变量
- 静态变量再内存中如何存储的。
- 静态变量的应用场景
- static修饰方法
- 成员方法的分类
- 静态方法的应用
- static的注意事项
- 综合小项目
面向对象快速入门
对象是一种特殊的数据结构,可以用来记住一个事物的数据,从而代表该事物。
我们知道我的数据可以通过变量或者数组存储,我们的对象也是存储数据的数据结构。
我们的变量存储数据
int max = 15;
数组存储数据
牛二, 西门, 全蛋
String[] names = {"牛二", "西门", "全蛋"} ;
// 或者
String[] names= new String[]{"牛二", "西门", "全蛋"};
对象存储 : 这个也是new 。但是我们下面的报错这是为什么。我们的对象格式不能凭空而来需要我们创建。
package com.hsh.object1;
public class main {public static void main(String[] args) {// 创建赵丽颖的Star对象并设置属性Star s1 = new Star();s1.name = "赵丽颖";s1.age = 36;s1.height = 165.0;s1.weight = 44.6;// 创建杨幂的Star对象并设置属性Star s2 = new Star();s2.name = "杨幂";s2.age = 37;s2.height = 166.5;s2.weight = 45.0;}
}
设计对象模版
- 先设计对象的模板,也就是对象的设计图:类。
package com.hsh.object1; // 明星类 ,明星对象模版 public class Star {String name;int age;double height;double weight; }
- 通过new关键字,每new一次类就得到一个新的对象
package com.hsh.object1; public class main {public static void main(String[] args) {String[] names= new String[]{"牛二", "西门", "全蛋"};// 创建赵丽颖的Star对象并设置属性Star s1 = new Star();s1.name = "赵丽颖";s1.age = 36;s1.height = 165.0;s1.weight = 44.6;// 创建杨幂的Star对象并设置属性Star s2 = new Star();s2.name = "杨幂";s2.age = 37;s2.height = 166.5;s2.weight = 45.0;System.out.println(s1.name);} }
接下来我们使用一个案例来了解一下对象的使用
Student.java
package com.hsh.object2;
public class Student {public String name;// 语文成绩public double chinese;// 数学成绩public double math;public void printTotalScore(){System.out.println(name + "的总成绩:" + (chinese + math));}public void printAverageScore(){System.out.println(name + "的平均成绩:" + (chinese + math) / 2);}
}
Test.java
package com.hsh.object2;
public class Test {public static void main(String[] args) {Student s1 = new Student();s1.name = "张三";s1.chinese = 100;s1.math = 100;s1.printTotalScore(); // 张三的总成绩:200.0s1.printAverageScore(); // 张三的平均成绩:100.0System.out.println("======================");Student s2 = new Student();s2.name = "李四";s2.chinese = 59;s2.math = 100;s2.printTotalScore();// 李四的总成绩:159.0s2.printAverageScore();// 李四的平均成绩:79.5}
}
啥是对象?深入理解对象
对象本质上是一种特殊的数据结构(可以理解成一张表)。
class也就是类,也称为对象的设计图(或者对象的模板)。
我们的对象相当于我们的模版表
而我们的new new Student();相当于重新打印一张没有填过数据的空表。
对象在计算机中是啥?
我们知道我的java在JVM中运行,而jJVM在我们电脑的内存中跑。
所以就是我们的java在内存的JVM虚拟机中运行。
JVM会把我们的内存分为:
划分区域 | 作用 |
---|---|
方法区 | 存放类文件,对象模版(也是类文件的一种) |
栈 | 用于存放方法,对象地址。先进后出,后进先出。 |
堆 | 存放实例化对象 |
我们下面来分析一下对象在计算机内存如何运行的。
- 当我们加载test类的时候。会把test放入方法区。
- 程序继续往下执行,把Test类中的main方法放入栈中
- 程序继续往下执行 Student s1 = new Student(); 这个语句虽然短但是在内存中的存放很复杂。
- 首先会将Student类文件放入方法区中。如下图的线1。
- 然后把s1引用类型(也就是是s1的地址)放入栈内存。如下图的线2。
- 最后new Student(也就是仿照对象模版创建的表,由于没有赋值,这个新表里的值都是默认值)会放入堆内存。如下图的线3。
- s1的值=创建的新表的地址。而新表中除了存放对象属性,还开辟了一小块空间存放了Student类文件的地址。
- 给新表赋值。
- 调用对象中的方法。首先在栈中地址–>堆中地址–> 类文件的方法 。类文件中的方法放入占内存中的main中运行。打印总分数和平均分后。销毁方法1和方法2。即后进先出。
- 剩下的就和之前一样了
面向对象编程是啥?
万物皆对象,谁的数据谁存储。
比如说我市场上的手机。每个手机都有自己独有的属性。那么手机就是一个对象。手机可以有名称,价格。
再比如说,王者荣耀的人物,都有名字。我们的血条下降是数据表中的数值在下降。
注意:我们设计对象,就是设计类。我们在设计类的时候会有很多语法。这些语法支持我们设计出更好的对象模版。下面学的类的基本语法,封装,继承目的只是做一个更好的对象。(重点)
类的基本语法
我们设计对象就是设计类。下面都是为了支撑设计出更好的类的模版,即设计更好的类。
构造器
构造器是什么样子?
本质是一种特殊的方法。构造器 名称必须和类名一致,而且没有返回值。
有参构造器和无参构造器,构造器重载。
public class Student {/** 无参构造器 */public Student(){System.out.println("无参构造器执行了");}/** 有参构造器 */public Student(String n ){System.out.println("我是有参构造器,参数是:"+n);}public Student(String n ,int a){System.out.println("我是有参构造器,参数是:"+n+"和"+a);}
}
构造器有什么特点?
创建对象时,对象会去调用构造器。调用哪个构造器有传递的参数决定。
// Test.java
public static void main(String[] args) {Student s1 = new Student(); // 无参构造器执行了Student s2 = new Student("hah"); // 我是有参构造器,参数是:hahStudent s3 = new Student("hsh",18); // 我是有参构造器,参数是:hsh和18
}
// Student.java
public class Student {/** 无参构造器 */public Student(){System.out.println("无参构造器执行了");}/** 有参构造器 */public Student(String n ){System.out.println("我是有参构造器,参数是:"+n);}public Student(String n ,int a){System.out.println("我是有参构造器,参数是:"+n+"和"+a);}
}
构造器的注意事项
- 类默认就自带了一个无参构造器
- 如果为类定义了有参数构造器,类默认的无参数构造器就没有了,此时如果还想用无参数构造器,就必须自己手写一个无参数构造器出来。比如上面把无参构造器删除。Test.java中的
Student s1 = new Student();
报错。这也从侧面说明了类默认就自带了一个无参构造器。不然我们上一节的面向对象入门的Student s1 = new Student();
也会报错。
构造器的常见应用场景?
创建对象时,同时完成对对象成员变量(属性)的初始化赋值。简化代码。
请看下面的代码:当我们的对象有多个属性不用一个一个的.出来。我们可以直接在()中赋值,类中的成员变量就可以接收。
// Test.java
public static void main(String[] args) {Student s1 = new Student();s1.name = "张三";s1.age = 18;System.out.println(s1.name+":"+s1.age); // 张三:18Student s2 = new Student("李四",18);System.out.println(s2.name+":"+s2.age); // 李四:18
}
// Student.java
public class Student {// 类中的变量叫做成员变量。String name;int age;public Student(){ }public Student(String n ,int a){name = n;age = a;}
}
this
this是什么
this就是一个变量,可以用在方法中,来拿到当前对象。
// Test.java
public static void main(String[] args) {Student s1 = new Student();s1.name = "张三";s1.print(); //com.itheima.thisdemo.Student@3b07d329 张三System.out.println(s1); // com.itheima.thisdemo.Student@3b07d329Student s2 = new Student();s2.print(); //com.itheima.thisdemo.Student@41629346 nullSystem.out.println(s2); // com.itheima.thisdemo.Student@41629346}
// Student.java
public class Student {// 成员变量String name;public void print(){// this是一个变量,用在方法中,用于拿到当前对象。// 哪个对象调用这个方法,this就拿到哪个对象。System.out.println(this);System.out.println(this.name);}
}
this有啥应用场景
this主要用来解决:用来解决对象的成员变量与方法内部变量的名称一样时,导致访问冲突问题的。
// Test.java
public static void main(String[] args) {Student s1 = new Student();s1.name = "张三";s1.print(); //com.itheima.thisdemo.Student@3b07d329 张三System.out.println(s1); // com.itheima.thisdemo.Student@3b07d329Student s2 = new Student();s2.print(); //com.itheima.thisdemo.Student@41629346 nullSystem.out.println(s2); // com.itheima.thisdemo.Student@41629346System.out.println("==========================");Student s3 = new Student();s3.name = "汪苏泷";s3.printHobby("唱歌!");}
// Student.java
public class Student {// 成员变量String name;public void print(){// this是一个变量,用在方法中,用于拿到当前对象。// 哪个对象调用这个方法,this就拿到哪个对象。System.out.println(this);System.out.println(this.name);}// 局部变量public void printHobby(String name){System.out.println(this.name + "喜欢" + name);}
}
封装
面向对象的三大特征:封装、继承、多态。
1、什么是封装?
就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理这些数据的方法,设计到一个对象中去。类就是一种封装。
2、我们为什么要封装呢? 下面来具体说明
// Test.java
public class Test {public static void main(String[] args) {Student s1 = new Student();s1.age = -19;s1.chinese= -98;// 我们的属性可以随意更改值。还可输入不符合条件的值。这样很不安全。// 我们需要把我们的值封装起来。}
}// Student.java
public class Student {String name;int age;double chinese;double math;public void printAllScore(){System.out.println(name + "的总成绩是:" +(chinese + math));}public void printAverageScore(){System.out.println(name + "的平均成绩是:" +(chinese + math) / 2);}
}
3、封装的设计规范是什么样的?
合理隐藏,合理暴露。
4、代码层面如何控对象的成员公开或隐藏?
公开成员,可以使用public(公开)进行修饰。
隐藏成员,使用private(私有,隐藏) 进行修饰。
// Test.java
public class Test {public static void main(String[] args) {// 学会如何隐藏如何暴露。Student s1 = new Student();s1.setAge(19); // 赋值System.out.println(s1.getAge()); // 取值}
}// Student.java
public class Student {String name;// 1、如何隐藏:使用private关键字(私有,隐藏)修饰成员变量,就只能在本类中被直接访问,// 其他任何地方不能直接访问。private int age;private double chinese;private double math;// 2、如何暴露(合理暴露):使用public修饰(公开)的get和set方法合理暴露// 成员变量的取值和赋值。// 这里的校验判断数值是否合法。可以不写,以后会在其他地方写。public void setAge(int age){ // 为年龄赋值if(age > 0 && age < 200){this.age = age;}else {System.out.println("您赋值的年龄数据非法!");}}public int getAge(){ // 获取年龄return age;}public void setChinese(double chinese) {this.chinese = chinese;}public double getChinese() {return chinese;}public void printAllScore(){System.out.println(name + "的总成绩是:" +(chinese + math));}public void printAverageScore(){System.out.println(name + "的平均成绩是:" +(chinese + math) / 2);}
}
Javabean
是一种特殊类,类中要满足如下需求
- 类中的成员变量全部私有,并提供public修饰的getter/setter方法
- 类中需要提供一个无参数构造器,有参数构造器可选
生成getter/setter方法和构造器的方法
打开你要生成的类,在这个类里面右击生成==>构造函数或者getter/setter方法选中即可
或者快捷键alt+insert
// Student.java
public class Student {// 1、成员变量需要私有private String name;private int age;private char sex;private double math;private double english;// 3、必须提供无参构造器。有参数构造器可有可无的。public Student() { }public Student(String name, int age, char sex, double math, double english) {this.name = name;this.age = age;this.sex = sex;this.math = math;this.english = english;}// 2、必须提供getter和setter方法。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;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}public double getMath() {return math;}public void setMath(double math) {this.math = math;}public double getEnglish() {return english;}public void setEnglish(double english) {this.english = english;}
}
实体类有啥应用场景?
我们之前是把求平均值和求总成绩的方法都写入Student类
中了。我们实体类不要写这些方法。就单纯对数据存和取两种功能即可。
// Student.java
public class Student {private String name;private int age;private char sex;private double math;private double english;// 为了减少代码长度。//无参构造器,有参数构造器,getter和setter方法不在写
}
// StudentOperator.java
/** 学生业务操作对象:负责对学生的数据进行业务处理 */
public class StudentOperator {private Student s; // 记住要操作的学生对象。// 类比private int a;public StudentOperator(Student s) {this.s = s;}public void printAllScore() {System.out.println(s.getName() + "总成绩是:" + (s.getMath() + s.getEnglish()));}public void printAverageScore() {System.out.println(s.getName() + "平均成绩是:" + (s.getMath() + s.getEnglish()) / 2);}
}
// Test.java
public class Test {public static void main(String[] args) {// 实体类的基本作用:创建对象、封装数据。// 1、通过无参数构造器初始化对象Student s2 = new Student();s2.setName("播仔");s2.setMath(50);s2.setEnglish(100);// 2、创建学生操作对象,处理学生的数据StudentOperator operator = new StudentOperator(s2);operator.printAllScore(); // ALT + ENTERoperator.printAverageScore();}
}
运行流程如下
- 把实例化对象(播仔,59,80)的地址给s2
- 通过实例化StudentOperator把s2地址传入StudentOperator中
- StudentOperator接收
- 接收后通过构造函数给StudentOperator。
- StudentOperator的成员变量s成功接收。
- 最终结果StudentOperator的成员变量s指向Test.java中的
new Student("播仔",59,80)
实体类的对象只负责数据存取,而对数据的处理交给其他类的对象来完成,以实现数据和数据业务处理相分离。
static关键字
static叫静态,可以修饰成员变量、成员方法。
static修饰成员变量
成员变量按照有无static修饰,分为两种:
- 静态变量(类变量):有static修饰,属于类,与类一起加载一次,在内存里只有一份,会被类的全部对象共享。
- 实例变量(对象的变量):无static修饰,属于每个对象的。每个对象中都有一份,只能用对象访问。
public class Student {// 静态变量:有static修饰,属于类,只加载一份,// 可以被类和类的全部对象共享访问static String name;// 实例变量:没有static修饰,属于对象,每个对象都有一份int age;
}
如果还不理解可以看下面的图。
如何访问静态变量
类名.静态变量 (推荐)
对象.静态变量(不推荐)
如何访问实例变量
对象.实例变量
静态变量再内存中如何存储的。
// Student.java
public class Student {// 静态变量:有static修饰,属于类,只加载一份,// 可以被类和类的全部对象共享访问static String name;// 实例变量:没有static修饰,属于对象,每个对象都有一份int age;
}
package com.itheima.staticfield;
// Test.java
public class Test {public static void main(String[] args) {// 1、类名.静态变量(推荐)Student.name = "袁华";System.out.println(Student.name);// 袁华// 2、对象名.静态变量(不推荐)Student s1 = new Student();s1.name = "马冬梅";Student s2 = new Student();s2.name = "秋雅";System.out.println(s1.name); // 秋雅System.out.println(Student.name); // 秋雅// 3、对象名.实例变量s1.age = 23;s2.age = 18;System.out.println(s1.age); // 23// System.out.println(Student.age); // 报错!}
}
- 第一步
- 第二步
- 第三步
- 第四步
- 第5步
- 第六步
- 第七步
8.第八步
9第九步
10 第十步
静态变量的应用场景
如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成静态变量来记住。
案例:系统启动后,要求用户类可以记住自己创建了多少个用户对象了。
// User.java
public class User {public static int count = 0;public User(){// User.count++;// 注意:同一个类中访问静态成员可以省略类名不写count++;}
}
// Test2.java
public class Test2 {public static void main(String[] args) {// 目标:了解静态变量的应用。new User();new User();new User();new User();System.out.println(User.count);}
}
访问自己类中的类变量,是否可以省略类名不写
count++;
在某个类中访问其他类里的类变量,必须带类名访问User.count++;
static修饰方法
成员方法的分类
-
静态方法:有static修饰的成员方法,属于类。
-
实例方法:无static修饰的成员方法,属于对象。
下面使用代码来解释
// Student.java
public class Student {private double score;// 静态方法:有static修饰,属于类持有。没有使用了成员变量public static void printHelloWorld(){System.out.println("Hello World");System.out.println("Hello World");System.out.println("Hello World");}// 实例方法:没有static修饰,属于对象持有。使用了成员变量public void printPass(){System.out.println(score >= 60 ? "通过了" : "您挂科了!");}public void setScore(double score) {this.score = score;}
}
// Test.java
public class Test {public static void main(String[] args) {// 1、类名.静态方法(推荐)Student.printHelloWorld();// 2、对象.静态方法(不推荐)Student s1 = new Student();s1.printHelloWorld();// 3、对象名.实例方法// Student.printPass(); // 报错s1.setScore(59.5);s1.printPass();}
}
注意:什么时候使用静态方法什么时候使用实例方法
如果这个方法只是为了做一个功能且不需要直接访问对象的数据,这个方法直接定义成静态方法。比如printHelloWorld();
没有使用成员变量。
如果这个方法是对象的行为,需要访问对象的数据,这个方法必须定义成实例方法。比如printPass();
使用成员变量。
思考:我们的main方法是什么方法?它是如何跑起来的?
答:静态方法。当我们点击运行时调用Test.main()运行。
main并没有使用成员变量。它具有启动我们程序的功能。所以他是静态的。
public class Test {public static void main(String[] args) {printHelloWorld2();// 本质调用 Test.printHelloWorld2();}public static void printHelloWorld2(){System.out.println("Hello World");System.out.println("Hello World");System.out.println("Hello World");System.out.println("Hello World");}
}
静态方法的应用
静态方法的常见应用场景
答:做工具类。
工具类是什么?
答:工具类中的方法都是一些静态方法,每个方法用来完成一个功能,以便供给开发人员直接使用。
使用类方法来设计工具类有啥好处?
答:提高了代码复用;调用方便,提高了开发效率。
public class XxxxUtil {public static void xxx(){ ...... }public static boolean xxxx(String email){ ... } public static String xxxxx(int n){ ... }...
}
为什么工具类中的方法要用静态方法,而不用实例方法?
答:实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,这样会浪费内存。静态方法,直接用类名调用即可,调用方便,也能节省内存。
工具类定义时有什么要求?
工具类没有创建对象的需求,建议将工具类的构造器进行私有。
// XxxxUtil.java
public class XxxxUtil {// 工具类没有创建对象的必要性,所以建议私有化构造器private XxxxUtil () {}
}
// Test.java
public class Test {public static void main(String[] args) {// 报错,因为XxxxUtil构造方法私有化,不能使用。// XxxxUtil x = new XxxxUtil();}
}
static的注意事项
- 静态方法中可以直接访问静态成员,不可以直接访问实例成员。
public class Test4 { // 静态变量 public static int count = 100; // 静态方法 public static void printHelloWorld2(){System.out.println("Hello World!"); } // 实例变量 :属于对象的。 private String name; // 实例方法 :属于对象的。 public void run(){ }public static void main(String[] args) {printHelloWorld(); }// 1、静态方法中可以直接访问静态成员,不可以直接访问实例成员。 public static void printHelloWorld(){System.out.println(count); // 100printHelloWorld2();// Hello World!// System.out.println(name); // 报错// 静态属性要想使用必须要先创建对象。Test4 t = new Test4();System.out.println(t.name);//null// run(); // 报错t.run();// System.out.println(this); // 报错。this代表的只能是对象。 }// 2、实例方法中既可以直接访问静态成员,也可以直接访问实例成员。 // 3、实例方法中可以出现this关键字,静态方法中不可以出现this关键字的。 // public void go(){ // System.out.println(count); // printHelloWorld2(); // System.out.println(name); // run(); // System.out.println(this); // } }
- 实例方法中既可以直接访问静态成员,也可以直接访问实例成员。
- 实例方法中可以出现this关键字,静态方法中不可以出现this关键字的。
public class Test4 { // 静态变量 public static int count = 100; // 静态方法 public static void printHelloWorld2(){System.out.println("Hello World!"); } // 实例变量 :属于对象的。 private String name; // 实例方法 :属于对象的。 public void run(){ }public static void main(String[] args) {} // 2、实例方法中既可以直接访问静态成员,也可以直接访问实例成员。 // 3、实例方法中可以出现this关键字,静态方法中不可以出现this关键字的。public void go(){System.out.println(count);printHelloWorld2();System.out.println(name);run();System.out.println(this);} }
综合小项目
// Movie.java
public class Movie {private int id;private String name;private double price;// 此处省略有参,无参构造,getter和setter方法
}
// MovieService.java 处理业务逻辑。
import java.util.Scanner;
public class MovieService {Movie[] movies;public MovieService(Movie[] movies){this.movies = movies;}// 展示所有电影信息public void showAllMovies(){for(int i = 0; i < movies.length; i++){System.out.println("电影id:"+movies[i].getId()+",电影名:"+movies[i].getName()+",电影价格:"+movies[i].getPrice());}}// 根据id查询电影public void findMovieById(){Scanner sc = new Scanner(System.in);System.out.println("请输入要查询的电影id");int id = sc.nextInt();for(int i = 0; i < movies.length; i++){if(movies[i].getId() == id){System.out.println("电影id:"+movies[i].getId()+",电影名:"+movies[i].getName()+",电影价格:"+movies[i].getPrice());return;}}System.out.println("没有找到该电影");}
}// Main.java
public class Main {public static void main(String[] args) {Movie[] movies = new Movie[5];movies[0] = new Movie(1, "战狼2", 29.6);movies[1] = new Movie(2, "哪吒2", 49.6);movies[2] = new Movie(3, "名侦探柯南", 39.6);movies[3] = new Movie(4, "马里奥", 19.6);movies[4] = new Movie(5, "冰雪奇缘", 54.6);MovieService movieService = new MovieService(movies);movieService.showAllMovies();movieService.findMovieById();}
}