Java基础之面向对象(上)
目录
一.面向过程与面向对象
1.面向过程(POP) 与 面向对象(OOP)
二者都是一种思想,面向对象是相对于面向过程而言的。
面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等。
2.面向对象的三大特征
封装 (Encapsulation)
继承 (Inheritance)
多态 (Polymorphism)
3.面向对象的思想概述
程序员从面向过程的执行者转化成了面向对象的指挥者
面向对象分析方法分析问题的思路和步骤:
根据问题需要,选择问题所针对的现实世界中的实体。
从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
二.Java基本元素:类和对象
1.面向对象的思想概述
类(Class)和对象(Object)是面向对象的核心概念
类是对一类事物的描述,是抽象的、概念上的定义
对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
“万事万物皆对象”
可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人
面向对象程序设计的重点是类的设计
类的设计,其实就是类的成员的设计
2.Java类及类的成员
1.现实世界的生物体,大到鲸鱼,小到蚂蚁,都是由最基本的细胞构成的。同 理,Java代码世界是由诸多个不同功能的类构成的。
2.现实生物世界中的细胞又是由什么构成的呢?细胞核、细胞质、… 那么, Java中用类class来描述事物也是如此。常见的类的成员有:
属 性:对应类中的成员变量
行 为:对应类中的成员方法
3.创建Java自定义类
步骤:
1. 定义类(考虑修饰符、类名)
2. 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
3. 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
三.对象的创建和使用
1.内存解析
编译完源程序以后,生成一个或多个字节码文件。我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味看,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
虚拟机栈,即为平时提到的栈结构。我们将局部变量存储在栈结构中。
堆,我们将new出来的结构(比如:数组、对象)加载在堆空间中。补充:对象的属性(非static的)加载在堆空间中。
方法区:类的加载信息、常量池、静态域
package com.oop.test;
/*
* 类的设计,其实就是类的成员的设计
*
* 创建类的对象=类的实例化=实例化类
*
* 如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性,(非static的)
* 意味着,如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
*/
public class PersonTest {
public static void main(String[] args) {
//创建Person类的对象
Person p1 =new Person();
//Scanner scan = new Scanner(System.in);
//调用对象的结构:属性和方法
//调用属性:“对象.属性”
p1.age = 10;
p1.isMale = true;
p1.name ="tom";
System.out.println(p1.name);
//调用方法:“对象.方法”
p1.eat();
p1.sleep();
p1.talk("chinese");
//.......................
Person p2 = new Person();
System.out.println(p2.name); //tom? null? null?
System.out.println(p2.isMale);//false
//................
//将p1变量保存的对象地址值赋给p3,导致p1和p3指向堆空间中的同一个对象实体
Person p3 =p1;
System.out.println(p3.name); //tom
p3.age =12;
System.out.println(p1.age); //12
}
}
class Person{
//属性
String name;
int age =1;
boolean isMale;
//方法
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
public void talk(String language){
System.out.println("说话,使用的是:"+language);
}
}
四.类的成员之一:属性(field)
1.变量的分类:成员变量与局部变量
成员变量(属性)和局部变量的区别?
2.成员变量vs局部变量的内存位置
3.对象属性的默认初始化赋值
4.代码演示
package com.oop.test;
/*
* 类中属性的使用
* 属性(成员变量) VS 局部变量
*1.相同点:
* 1.1. 定义变量的格式: 数据类型 变量名 = 变量值
* 1.2. 先声明,后使用
* 1.3. 变量都有其对应的作用域
*
* 2.不同点:
* 1.1. 在类中声明的位置不同
* 属性: 直接定义在类的一对{}内
* 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
*
* 2.2.关于权限修饰符的不同
* 属性:可以在声明属性时,指明其权限,使用权限修饰符
* 常用的权限修饰符:private, public、 缺省、 protected-------》封装性
* 目前,使用缺省就可以了
* 局部变量:不可以使用权限修饰符
*
* 2.3 默认初始化值的情况
* 属性:类的属性、根据其类型都有默认初始化值
* 整型 0
* 浮点型:0.0
* 字符型:0(或“|u0000”)
* 布尔型:false
*
* 引用数据类型(类、数组、接口):null
*
* 局部变量:没有默认初始化值
* 意味着,我们在调用局部变量之前,一定要显示赋值
* 特别地,形参在调用时, 赋值即可。
*
* 2.4.在内存中加载的位置不同
* 属性:加载到堆空间中(非static)
* 局部变量:加载到栈空间中
*
*
*/
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
System.out.println(u1.age);
System.out.println(u1.name);
System.out.println(u1.isMale);
u1.talk("chinese");
}
}
class User{
//属性(成员变量)
// private String name; 权限问题
String name;
public int age;
boolean isMale;
public void talk(String language){//language:形参,也是局部变量
System.out.println("我们使用"+ language);
}
public void eat(){
String food = "烙饼";// 局部变量
System.out.println("北方人喜欢吃:"+food);
}
}
五.类的成员之二:方法
1.什么是方法(method、函数)
方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中 也称为函数或过程。
将功能封装为方法的目的是,可以实现代码重用,简化代码
Java里的方法不能独立存在,所有的方法必须定义在类里。
2.注 意:
方法被调用一次,就会执行一次
没有具体返回值的情况,返回值类型用关键字void表示,那么方法体中可以不必使用return语句。如果使用,仅用来结束方法。
定义方法时,方法的结果应该返回给调用者,交由调用者处理。
方法中只能调用方法或属性,不可以在方法内部定义方法。
3.代码演示
package com.oop.test;
/*
* 类中方法的声明和使用
*
* 方法:描述类具有的功能
*
* 方法的声明:权限修饰符 返回值类型 方法名(){形参列表}
* 方法体
*
* 注意: static、fina;、 abstract 来修饰方法
* 说明:
* 1.权限修饰符:
* java规定的四种权限修饰符:private public 缺省 protected (封装性细说)
*
* 2.返回值共型,有返回值VS没有返回值
* 如果方法有返回值,必须在方法声明时,指定返回值的类型。
* 同时,方法中,需要使用return关健字来返回指定类型的度量或常量,
*
* 如果方法没有返回值,则方法声明制,使用V⊙1d来表示。通常,没有返回值的方法中,
* 不需要使用return, 但如果使用的话。只能"return;'表示编使此方法的意思,
*
* 我们定义万法该不该有返回值?
①题目要求
②凭借经出,具体问题县体分折
*
* 3.方法名:属于标识符,遵循标识符的规侧和规范,“见名知意”
*
* 4.形参列表:方法可以声明日个,1个,或多个形参。
格式:数据类型1形参1,数据类型2形参2,···
我们定义方法时,该不该定义形参?
①题目要求
②凭经验:具体问题具体分析
*
* 5.return关键字的使用:
1.使用范围:使用在方法体中
2.作用: ② 结束方法
② 针对于有返回值类型的方法,使用"return数据"方法返回所要的数据。
3.注意点:return关键字后面不可以声明执行语句。
* 6.方法的使用中,可以调用当前类的属性或方法
特殊的:方法A中又调用了方法A:递归方法。
方法中,不可以定义方法。
*/
public class CustomerTest {
public static void main(String[] args){
Customer cust1 = new Customer();
cust1.eat();
}
}
class Customer{
//属性
String name;
int age;
boolean isMale;
//方法:
public void eat(){
System.out.println("客户吃饭");
}
public void sleep(int hour){
System.out.println("休息了" + hour + "个小时");
return;
//return之后不能到达
//System.out.println("后面不能再写了");
}
public String getName(){
return name;
}
public String getNation(String nation){
String info = "我的国籍" + nation;
return info;
}
}
4.练习题
基础版
package com.oop.test1;
/*
* 4. 对象数组题目:
定义类Student,包含三个属性:学号number(int),年级state(int),成绩
score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
*/
public class StudentTest {
public static void main(String[] args) {
//声明Student类型的数组
Student[] stus = new Student[20];
for (int i = 0; i< stus.length;i++){
//给数组元素赋值
stus[i] = new Student();
//给对象的属性赋值
stus[i].number = i+1;
//年级【1,6】
stus[i].state = (int)(Math.random() * (6-1+1) + 1);
//成绩【0,100】
stus[i].score = (int)(Math.random() * (100-0+1));
}
//遍历学生数组
for(int i =0;i<stus.length;i++){
System.out.println(stus[i].number +"," + stus[i].state+
","+stus[i].score);
System.out.println(stus[i].info());
}
System.out.println("*****************");
//问题一:打印出3年级(state值为3)的学生信息
for(int i =0; i<stus.length;i++){
if(stus[i].state == 3){
System.out.println(stus[i].info());
}
}
System.out.println("*****************");
//问题二:
for(int i =0;i<stus.length-1;i++){
for(int j = 0;j < stus.length-1-i;j++){
if(stus[j].score > stus[j+1].score){
//如果要换序,交换的是数组元素,Student对象
Student temp = stus[j];
stus[j] =stus[j+1];
stus[j+1]= temp;
}
}
}
//遍历学生信息
for(int i = 0; i<stus.length;i++){
System.out.println(stus[i].info());
}
}
}
class Student{
int number;
int state;
int score;
//显示学生信息的方法
public String info(){
return "学号:" + number + "年级:" + state + "成绩:" + score;
}
}
进阶版
package com.oop.test1;
public class StusTest {
public static void main(String[] args) {
//声明Student类型的数组
Student1[] stus = new Student1[20];
for (int i = 0; i< stus.length;i++){
//给数组元素赋值
stus[i] = new Student1();
//给对象的属性赋值
stus[i].number = i+1;
//年级【1,6】
stus[i].state = (int)(Math.random() * (6-1+1) + 1);
//成绩【0,100】
stus[i].score = (int)(Math.random() * (100-0+1));
}
StusTest test = new StusTest();
//遍历
test.print(stus);
//三年级的学生信息
test.searchState(stus, 3);
//排序
test.sort(stus);
test.print(stus);
}
/**
*
* @Description //遍历Sthdent1[]数组的操作方法
* @author tyl
* @date 2023年2月21日下午8:40:57
* @param stus
*/
public void print(Student1[] stus){
for(int i =0;i<stus.length;i++){
System.out.println(stus[i].info());
}
System.out.println("*****************");
}
/**
*
* @Description //查找学生信息的方法
* @author tyl
* @date 2023年2月21日下午8:40:43
* @param stus
* @param state
*/
public void searchState(Student1[] stus, int state){
for(int i =0; i<stus.length;i++){
if(stus[i].state == state){
System.out.println(stus[i].info());
}
}
System.out.println("*****************");
}
/**
*
* @Description //给Student1数组排序
* @author tyl
* @date 2023年2月21日下午8:42:40
* @param stus
*/
public void sort(Student1[] stus){
for(int i =0;i<stus.length-1;i++){
for(int j = 0;j < stus.length-1-i;j++){
if(stus[j].score > stus[j+1].score){
//如果要换序,交换的是数组元素,Student对象
Student1 temp = stus[j];
stus[j] =stus[j+1];
stus[j+1]= temp;
}
}
}
}
}
class Student1{
int number;
int state;
int score;
//显示学生信息的方法
public String info(){
return "学号:" + number + "年级:" + state + "成绩:" + score;
}
}
六.再谈方法
方法的重载
1.重载的概念
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
2.重载的特点
与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类型)。调用时,根据方法参数列表的不同来区别。
3.代码演示
package com.wuchun.java;
/*
* 方法的重载(overloaad):loading...
*
* 1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
*
* "两同一不同”:同一个类、相同方法名
参数列表不同:参数个数不同,参数类型不同
2.举例:Arrays类中重载的sort()/binarySearch()
*
* 3.判断是否是重载:
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系
*
*
* 4. 在通过对象调用方法时,如何确定某一个指定的方法:
方法名-->参数列表
*/
public class OverLoadTest {
public static void main(String[] args) {
OverLoadTest test = new OverLoadTest();
test.getSum(1, 20); //自动类型提升
}
/* public void getSum(int i, int j){
System.out.println("1");
}
*/
public void getSum(String s, int i){
System.out.println("2");
}
public void getSum(double m ,double n){
System.out.println("3");
}
public void getSum(int i,String s){
System.out.println("4");
}
}
可变形参的方法
1.概念
JavaSE 5.0 中提供了Varargs(variable number of arguments)机制,允许直接定 义能和多个实参相匹配的形参。从而,可以用一种更简单的方式,来传递个数可变的实参。
//JDK 5.0以前:采用数组形参来定义方法,传入多个同一类型变量 public static void test(int a ,String[] books);
//JDK5.0:采用可变个数形参来定义方法,传入多个同一类型变量 public static void test(int a ,String…books);
2.说明
1. 声明格式:方法名(参数的类型名 ...参数名)
2. 可变参数:方法参数部分指定类型的参数个数是可变多个:0个,1个或多个
3. 可变个数形参的方法与同名的方法之间,彼此构成重载
4. 可变参数方法的使用与方法参数部分使用数组是一致的
5. 方法的参数部分有可变形参,需要放在形参声明的最后
6. 在一个方法的形参位置,最多只能声明一个可变个数形参
3.代码演示
package com.wuchun.java;
/*
* 可变个数形参
* 1.jdk5.0新增的内容
2.具体使用:
2.1可变个数形参的格式:数据类型 ... 变 量名
2.2当调用可变个数形参的方法时,传入的参数个数可以是:日个,1个,2个,。。。
2,3可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
2.4可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存
2.5可变个数形参在方法的形参中,必须声明在末尾
2.6可变个数形参在方法的形参中,最多只能声明一个可变形参不
*
*/
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show(12);
test.show("hello");
test.show("hello","word");
test.show();
test.show("aa","ss","as");
test.show(new String[]{"aa","ss","as"});
}
public void show(int i){
}
public void show(String s){
System.out.println("优先考虑一个参数");
}
public void show(String ... strs){
System.out.println("String ... strs");
for(int i = 0;i < strs.length;i++){
System.out.println(strs[i]);
}
}
/* public void show(String[] strs){
}*/
}
方法参数的值传递机制
1.概念
方法,必须由其所在类或对象调用才有意义。若方法含有参数:
形参:方法声明时的参数
实参:方法调用时实际传给形参的参数值
Java的实参值如何传入方法呢? Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本 (复制品)传入方法内,而参数本身不受影响。
形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
2.代码演
package com.wuchun.java;
/*
* 关于变量的赋值
*
* 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的做据的地址值。
*
*
*
*/
public class ValueTransferTest {
public static void main(String[] args) {
System.out.println("***************基本数据类型**************");
int m = 10;
int n = m;
System.out.println(n + m);
n = 20;
System.out.println(n + m);
System.out.println("***************引用数据类型**************");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1; //赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个对象实体。
System.out.println(o1.orderId+","+o2.orderId);
o2.orderId = 1002;
System.out.println(o1.orderId+","+o2.orderId);
}
}
class Order{
int orderId;
}
package com.wuchun.java;
/*
* 方法的形参的传递机制:值传递
1.形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
2.值传递机制:
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
*
*/
public class ValueTransferTest2 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println(data.m+",,,"+data.n);
//交换两个值
// int temp= data.m;
// data.m = data.n;
// data.n = temp;
ValueTransferTest2 test = new ValueTransferTest2();
test.swap(data);
System.out.println(data.m+",,,"+data.n);
}
public void swap(Data data){
int temp= data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
3.代码图示
4.习题练习
package com.wuchun.java;
/*
*
* (1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个
findArea()方法返回圆的面积。
*
*
*
*
*/
public class Circle {
double radius; //半径
//求圆面积
public double findArea(){
return Math.PI*radius*radius;
}
}
package com.wuchun.java;
/*
* (2)定义一个类PassObject,在类中定义一个方法printAreas(),该方法的定义
如下:public void printAreas(Circle c, int time)
在printAreas方法中打印输出1到time之间的每个整数半径值,以及对应的面积。
例如,times为5,则输出半径1,2,3,4,5,以及对应的圆面积。
(3)在main方法中调用printAreas()方法,调
用完毕后输出当前半径值。程序运行结果如图所示。
*
*
*
*/
public class PassObject {
public static void main(String[] args) {
PassObject test = new PassObject();
Circle c = new Circle();
test.printAreas(c, 5);
System.out.println("now radius is " + c.radius);
}
public void printAreas(Circle c, int time){
System.out.println("Radius\t\tArea");
for(int i =1; i<= time; i++){
//设置圆的半径
c.radius = i;
System.out.println(c.radius + "\t\t" + c.findArea());
}
c.radius = time +1;
}
}
递归方法
1.概念
递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
2.代码演示
package com.tyl.java2;
/*
* 递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执
行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死
循环。
*
*
*
*
*/
public class RecursionTest {
public static void main(String[] args) {
RecursionTest test = new RecursionTest();
int sum = test.getSum(100);
System.out.println(sum);
System.out.println(test.getSum(100));
System.out.println(test.getSum1(100));
System.out.println(test.f(10));
}
//例1:计算1-n之间所有自然数的和
public int getSum(int n){
if (n == 1){
return 1;
}else{
return n + getSum(n-1);
}
}
//例2:计算1-n之间所有自然数的乘积:n!
public int getSum1(int n){
if (n ==1){
return 1;
}else {
return n * getSum1(n-1);
}
}
//例3:已知有-个数列:f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),
//其中n是大于0的整数,求f(10)的值。
public int f(int n){
if (n ==0){
return 1;
}else if(n ==1){
return 4;
}else {
return 2*f(n-1)+f(n-2);
}
}
//例4:斐波那契数列
//例5:汉诺塔问题
//例6:快排(像二分法)
}
3.习题学习
七.OOP特征一:封装与隐藏
1.引例
2.代码演示
package com.tyl.java;
/*
* 面向对象的特征一:封装与隐藏
一、问题的引入:
*
*
* 二、封装性的体现:
* 拓展:封装性的体现:①如上
* ②不对外暴露的私有的方法
* ③单例模式
*
* 三、封装性的体现,需要权限修饰符来配合。
1.JaVa规定的4种权限(从小到大排列):private、缺省、protected、public
2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
修饰类的话,只能使用:缺省、public
*/
public class AnimaTest {
public static void main(String[] args) {
Animal test = new Animal();
test.age = 1;
test.name = "tyl";
//test.legs = 4; //The field Animal.legs is not visible
test.show();
//test.legs = -4; //The field Animal.legs is not visible
test.show();
test.setLegs(6);
test.show();
test.setLegs(-4); // 赋值负数
test.show();
//test.legs1 = -8; //The field Animal.legs is not visible
test.show();
System.out.println(test.name);
}
}
class Animal{
String name;
int age;
private int legs; // 修饰符:private
//对属性的设置
public void setLegs(int l){
if(l >= 0 && l % 2 == 0){
legs =l;
}else{
legs = 0; //抛出一个错误
}
}
//对属性的获取
public int geLegs(){
return legs;
}
public void show(){
System.out.println("name: "+ name +", age: " + age + ",legs:"+ legs );
}
}
3.习题练习
package com.chun.java;
/*
* 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。
*
*/
public class Person {
private int age;
public void setAge(int a){
if(a<0 || a>130){
System.out.println("传入的数据非法");
return;
}
age = a;
}
public int getAge(){
return age;
}
//绝对不要这样写!!!!!!!!!
public int doAge(int a){
age = a;
return age;
}
}
package com.chun.java;
/*
*
* 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
getAge()方法,体会Java的封装性。
*
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(12);
System.out.println("年龄为:"+ p1.getAge());
p1.doAge(22);
System.out.println("年龄为:"+ p1.getAge());
}
}
八.类的成员之三:构造器
1.构造器的特征
它具有与类相同的名称
它不声明返回值类型。(与声明为void不同)
不能被static、final、synchronized、abstract、native修饰,不能有return语句返回值
2.构造器的作用
创建对象;给对象进行初始化
如:Order o = new Order(); Person p = new Person(“Peter”,15);
如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的 构造器中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自 动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们 要“洗澡”了。
3.根据参数不同,构造器可以分为如下两类
隐式无参构造器(系统默认提供) 显式定义一个或多个构造器(无参、有参)
4.注 意
Java语言中,每个类都至少有一个构造器
默认构造器的修饰符与所属类的修饰符一致
一旦显式定义了构造器,则系统不再提供默认构造器
一个类可以创建多个重载的构造器
父类的构造器不可被子类继承
5.代码演示
package com.wc.java;
/*
*
* 类的结构之三:构造器(或构造方法、constructor)的使用
construct:建设、建造。construction:CCB
constructor:建设者
一、构造器的作用:
1.创建对象
2.初始化对象的信息
二、说明:
1,如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦显示定义了类的构造器,系统不再提供默认的空参构造器
5.一个类中至少会有一个构造器
*
*/
public class PersonTest {
public static void main(String[] args) {
//创建类的对象:new+构造器
Person p = new Person();
p.eat();
Person p1 = new Person("tom");
System.out.println(p1.name);
}
}
class Person{
//属性
String name;
int age;
//构造器
public Person(){
System.out.println("Person()............");
}
public Person(String n){
name = n;
}
public Person(String n,int a){
name = n;
age = a;
}
public void eat(){
System.out.println("干饭");
}
}
6.练习
package com.wc.java;
/*
* .编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底
边长base和高height,同时声明公共方法访问私有变量。此外,提供类
必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
*/
public class TriAngle {
private double base;
private double height;
public TriAngle(){
}
public TriAngle(double b,double h){
base = b;
height = h;
}
public void setBase(double b){
base = b;
}
public double getBase(){
return base;
}
public void setHeight(double h){
height = h;
}
public double getHeight(){
return height;
}
}
package com.wc.java;
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t1 = new TriAngle();
t1.setBase(3.0);
t1.setHeight(4.0);
//t1.base = 2.5;
//t1.height = 4.3; //The field TriAngle.height is not visible
System.out.println("base: " + t1.getBase() + "heights: " + t1.getHeight());
TriAngle t2 = new TriAngle(2.6,3.5);
System.out.println("base: " + t2.getBase() + "heights: " + t2.getHeight());
}
}
7.构造器重载
构造器一般用来创建对象的同时初始化对象。如 class Person{ String name; int age; public Person(String n , int a){ name=n; age=a;} }
构造器重载使得对象的创建更加灵活,方便创建各种不同的对象。 构造器重载举例: public class Person{ public Person(String name, int age, Date d) {this(name,age);…} public Person(String name, int age) {…} public Person(String name, Date d) {…} public Person(){…} }
构造器重载,参数列表必须不同
8.总结:属性赋值过程
截止到目前,我们讲到了很多位置都可以对类的属性赋值。现总结这几个位 置,并指明赋值的先后顺序。
赋值的位置:
① 默认初始化 ② 显式初始化 ③ 构造器中初始化 ④ 通过“对象.属性“或“对象.方法”的方式赋值
赋值的先后顺序: ① - ② - ③ - ④
代码演示
package com.wc.java;
/*
* 总结:属性赋值的先后顺序
①默认初始化
②显式初始化
③构造器中赋值 都是初始化
④通过"对象,方法"或"对象,属性"的方式,赋值
以上操作的先后顺序:1、2、3、4
*
*
*
*
*/
public class UersTest {
public static void main(String[] args) {
User u = new User();
System.out.println(u.age);
User u1 = new User(2);
System.out.println(u1.age);
u1.setAge(3);
System.out.println(u1.age);
}
}
/**
*
* @Description
* @author tyl Email:1411566463@qq.com
* @version
* @date 2023年3月9日下午9:22:38
*
*/
class User{
String name;
int age = 1;
public User(){
}
public User(int a){
age = a;
}
public void setAge(int a){
age =a;
}
}
9.拓展知识:JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓javaBean,是指符合如下标准的Java类:
1.类是公共的
2.有一个无参的公共的构造器
3.有属性,且有对应的get、set方法
用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以 用Java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP 页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用 户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关 心任何改变。
代码演示
package com.wc.java;
/*
* JavaBean是一种Java语言写成的可重用组件。
所谓avaBean,是指符合如下标谁的Java类:
>类是公共的
>有一个无参的公共的构造器
>有属性,且有对应的get、set方法
*
*
*
*
*/
public class Customer {
private int id;
private String name;
public Customer(){
}
public void setId(int i){
id = i;
}
public int getId(){
return id;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
10.拓展知识:UML类图
九.关键字:this
1.概念
在Java中,this关键字比较难理解,它的作用和其词义很接近。
它在方法内部使用,即这个方法所属对象的引用;
它在构造器内部使用,表示该构造器正在初始化的对象。
this 可以调用类的属性、方法和构造器
什么时候使用this关键字呢? 当在方法内需要用到调用该方法的对象时,就用this。 具体的:我们可以用this来区分属性和局部变量。 比如:this.name = name;
2.代码演示
package com.tyl001.java;
/*
* this关键字的使用:
1.this可以用来修饰:属性、方法、构造器
2.this修饰属性和方法:
this理解为:当前对象 或者 当前正在创建的对象
2.1.在类的方法中,我们可以使用"this,属性"或"this,方法"的方式,调用当前对象属性或方法。但是,
通常情况下,我们都选择省略"th1s."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
的使用"this,变量"的方式,表明此变量是属性,而非形参。
2.2. 在类的构造器中也是如此
3.this调用构造器
@我们在类的构造器中,可以显式的使用"th1s(形参列表)"方式,调用本类中指定的其他构造器
@构造器中不能通过"this(形参列表)"方式调用自己
@如果一个类中有n个构造器,则最多有n1构造器中使用了"this(形参列表)"
④规定:"this(形参列表)"必须声明在当前构造器的首行
⑤构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
*
*/
public class PersonTset {
public static void main(String[] args) {
Person p = new Person();
p.setAge(2);
System.out.println(p.getAge());
p.eat();
System.out.println();
Person p2 = new Person("tyl",29);
System.out.println(p2.getAge());
}
}
class Person{
private String name;
private int age;
public Person(){
this.eat();
String info = "l love you";
System.out.println(info);
}
public Person(String name){
this();
this.name = name;
}
public Person(int age){
this();
this.age = age;
}
public Person(String name, int age){
this(age);
this.name = name;
//this.age = age;
}
public void setName(String name){ //属性与形参同名时,使用this关键字
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age; //当前对象的属性或者方法
}
public int getAge(){
return this.age;
}
public void eat(){
System.out.println("干饭");
this.study(); //方法内调用方法
}
public void study(){
System.out.println("学习");
}
}
3.习题学习
package com.tyl001.java;
public class Boy {
private String name;
private int age;
private double years;
//使用source里面直接生成构造器
public Boy() {
}
public Boy(String name, int age, double years) {
super();
this.name = name;
this.age = age;
this.years = years;
}
//使用source里面直接生成get和set方法
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 double getYears() {
return years;
}
public void setYears(double years) {
this.years = years;
}
public void marry(Gril gril){
System.out.println("qu"+ gril.getName());
}
public void shout(){
System.out.println("ok了");
}
}
package com.tyl001.java;
public class Gril {
private String name;
private int age;
public Gril() {
}
public Gril(String name, int age) {
this.name = name;
this.age = age;
}
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 void marry(Boy boy){
System.out.println("jia"+boy.getName());
boy.marry(this);
}
/**
*
* 比较两个对象的大小
*/
public int compare(Gril gril){
return this.age - gril.age;
}
}
package com.tyl001.java;
public class BoyTest {
public static void main(String[] args) {
Boy boy = new Boy("wc", 21, 2018);
boy.shout();
Gril gril = new Gril("tyl", 18);
gril.marry(boy);
Gril gril1 = new Gril("xx", 19);
int compare = gril.compare(gril1);
if(compare >0){
System.out.println(gril.getName() + "大");
}else if(compare <0){
System.out.println(gril1.getName() + "大");
}else{
System.out.println("me too");
}
}
}
4.实验1
造两个类
package com.wcc.java;
public class Account {
private int id; //账号
private double balance; //余额
private double annulInterestRate; //年利率
public Account(int id, double balance, double annulInterestRate){
this.id = id;
this.balance = balance;
this.annulInterestRate = annulInterestRate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getAnnulInterestRate() {
return annulInterestRate;
}
public void setAnnulInterestRate(double annulInterestRate) {
this.annulInterestRate = annulInterestRate;
}
public void withdraw (double amount){ //取钱
if(balance < amount){
System.out.println("余额不足");
return;
}
balance -= amount;
System.out.println("成功取出"+amount);
}
public void deposit (double amount){ //存钱
if (amount > 0){
balance += amount;
System.out.println("成功存入" + amount);
}
}
}
package com.wcc.java;
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String f,String l){
this.firstName = f;
this.lastName = l;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
测试类
测试类
package com.wcc.java;
/*
* 写一个测试程序。
(1) 创建一个 Customer ,名字叫 Jane Smith, 他有一个账号为 1000,余额为 2000 元,
年利率为 1.23% 的账户。
(2) 对 Jane Smith 操作。
存入 100 元,再取出 960 元。再取出 2000 元。
打印出 Jane Smith 的基本信息
*/
public class CustomerTest {
public static void main(String[] args) {
Customer cust = new Customer("jane", "Smith");
Account acct = new Account(1000, 2000, 0.0123);
cust.setAccount(acct);
cust.getAccount().deposit(100);
cust.getAccount().withdraw(960);
cust.getAccount().withdraw(2000);
System.out.println("Customer[" + cust.getLastName() + "," + cust.getFirstName() + "] has a amount : id is"
+ cust.getAccount().getId() + ",annual :"+
cust.getAccount().getAnnulInterestRate()*100 + "%,balance is"+ cust.getAccount().getBalance());
}
}
5.实验2
类1
package com.wcchun001.java;
public class Account {
private double balance;
public Account(double init_balance){
this.balance = init_balance;
}
public double getBalance(){
return balance;
}
//存钱
public void deposit(double amt){
if(amt>0){
balance += amt;
System.out.println("存钱成功");
}
}
//取钱操作
public void withdraw(double amt){
if(balance >= amt){
balance -= amt;
System.out.println("取钱成功");
}else{
System.out.println("余额不足");
}
}
}
类2
package com.wcchun001.java;
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String f,String l){
this.firstName = f;
this.lastName = l;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
类3
package com.wcchun001.java;
public class Bank {
private Customer[] customers;
private int numberOfCustomers;
public Bank(){
customers = new Customer[10];
}
//添加客户
public void addCustomer(String f,String l){
Customer cust = new Customer(f,l);
//customers[numberOfCustomers] = cust;
//numberOfCustomers++;
//或者
customers[numberOfCustomers++] = cust;
}
//获取客户个数
public int getNumOfCustomers(){
return numberOfCustomers;
}
//获取指定位置上的客户
public Customer getCustomer(int index){
//return customers[index];
if (index >=0 && index < numberOfCustomers){
return customers[index];
}
return null;
}
}
测试类
package com.wcchun001.java;
public class BankTest {
public static void main(String[] args) {
Bank bank = new Bank();
bank.addCustomer("yl", "t");
bank.getCustomer(0).setAccount(new Account(2000));
bank.getCustomer(0).getAccount().withdraw(500);
double balance = bank.getCustomer(0).getAccount().getBalance();
System.out.println("客户:"+bank.getCustomer(0).getFirstName() + "的余额为:"+ balance);
System.out.println("/");
bank.addCustomer("纯纯", "吴");
System.out.println("客户个数为:"+bank.getNumOfCustomers());
}
}
十.关键字:package、import
1.package概念
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在 的包。(若缺省该语句,则指定为无名包)。
它的格式为: package 顶层包名.子包名 ;
包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次;
包通常用小写单词标识。通常使用所在公司域名的倒置:com.atguigu.xxx
2.import概念
为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类 或全部类(.*)。import语句告诉编译器到哪里去寻找类。
语法格式: import 包名. 类名;
3.代码演示
package com.wcchun001.java;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;
import com.wcchun001.java2.Dog;
import java.util.*;
import static java.lang.System.*;
import static java.lang.Math.*;
/*
* 一、package关键字的使用
1,为了更好的实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包,属于标识符,遵循标识符的命名规侧、规范(xxxyyyzzz)、“见名知意”
4.每"."一次,就代表一层文件目录。
补充:同一个包下,不能命名同名的接口、类。
不同的包下,可以命名同名的接口、类。
*
*
* ニ、import键字用
import:导入
1,在源文件中显式的使用import结构导入指定包下的类、接口
2,声明在包的声明和类的声明之间
3,如果需要导入多个结构,则并列写出即可
4,可以使用"XXX,*"的方式,表示可以导入XXX包下的所有结构
5.如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6,如果使用的类或接口是本包下定义的,则可以省略import结构
7.如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
8.使用"XXX.*"方式表明可以调用XXX包下的所有结构。但是如果使用的是XXx子包下的结构,则仍需要导入该包下的结构。
9.import static:导入指定类或接口中的静态结构:属性或方法。
*
*
*
*/
public class PackageImportTest {
public static void main(String[] args) {
Arrays.toString(new int[]{1,2,3});
Bank bank = new Bank();
ArrayList list = new ArrayList();
HashMap map = new HashMap();
Scanner s = null;
System.out.println("hello");
Account acct = new Account(1000);
//全类名的方式显示
com.wcc.java.Account acct1 = new com.wcc.java.Account(200, 100, 0.123);
Date data = new Date();
java.sql.Date date1 = new java.sql.Date(21311);
Dog d = new Dog();
out.println("001");
long n = round(123.1212);
}
}
快捷键操作
package com.tyl.java;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
/*
* Eclipse中的快捷键:
* 1.补全代码的声明:alt + /
* 2.快速修复: ctrl + 1
* 3.批量导包:ctrl + shift + o
* 4.使用单行注释:ctrl + /
* 5.使用多行注释: ctrl + shift + /
* 6.取消多行注释:ctrl + shift + \
* 7.复制指定行的代码:ctrl + alt + down 或 ctrl + alt + up
* 8.删除指定行的代码:ctrl + d
* 9.上下移动代码:alt + up 或 alt + down
* 10.切换到下一行代码空位:shift + enter
* 11.切换到上一行代码空位:ctrl + shift + enter
* 12.如何查看源码:ctrl + 选中指定的结构 或 ctrl + shift + t
* 13.退回到前一个编辑的页面:alt + left
* 14.进入到下一个编辑的页面(针对于上面那条来说的):alt + right
* 15.光标选中指定的类,查看继承树结构:ctrl + t
* 16.复制代码: ctrl + c
* 17.撤销: ctrl + z
* 18.反撤销: ctrl + y
* 19.剪切:ctrl + x
* 20.粘贴:ctrl + v
* 21.保存: ctrl + s
* 22.全选:ctrl + a
* 23.格式化代码: ctrl + shift + f
* 24.选中数行,整体往后移动:tab
* 25.选中数行,整体往前移动:shift + tab
* 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl + o
* 27.批量修改指定的变量名、方法名、类名等:alt + shift + r
* 28.选中的结构的大小写的切换:变成大写: ctrl + shift + x
* 29.选中的结构的大小写的切换:变成小写:ctrl + shift + y
* 30.调出生成getter/setter/构造器等结构: alt + shift + s
* 31.显示当前选择资源(工程 or 文件)的属性:alt + enter
* 32.快速查找:参照选中的Word快速定位到下一个 :ctrl + k
*
* 33.关闭当前窗口:ctrl + w
* 34.关闭所有的窗口:ctrl + shift + w
* 35.查看指定的结构使用过的地方:ctrl + alt + g
* 36.查找与替换:ctrl + f
* 37.最大化当前的View:ctrl + m
* 38.直接定位到当前行的首位:home
* 39.直接定位到当前行的末位:end
*/
public class EclipseKeys {
public static void main(String[] args) {
// 补全代码的声明:alt + /
new String();
String n = "sasa";
String s = new String();
// 快速修复 ctrl + 1
String str = new String();
int Number = 1;
// 批量导包:ctrl + shift + o
ArrayList list12 = new ArrayList();
HashMap map = null;
Date date = new Date(11212313);
// * ArrayList list = new ArrayList(); HashMap map = null;
// *
// * Date date = new Date(11212313); ArrayList list = new ArrayList();
// * HashMap map = null;
// *
// * Date date = new Date(11212313);
// 使用单行注释:ctrl + /
// 使用多行注释: ctrl + shift + /
// 取消多行注释:ctrl + shift + \
// 复制指定行的代码:ctrl + alt + down 或 ctrl + alt + up
list12.add(1213);
list12.add(1213);
list12.add(1213);
list12.add(1213);
list12.add(1213);
// list.add(1213);
// list.add(1213);
// 上下移动代码:alt + up 或 alt + down
// 删除指定行的代码:ctrl + d
// 切换到下一行代码空位:shift + enter
// 切换到上一行代码空位:ctrl + shift + enter
// 如何查看源码:ctrl + 选中指定的结构 或 ctrl + shift + t
// 退回到前一个编辑的页面:alt + left
// 进入到下一个编辑的页面(针对于上面那条来说的):alt + right
// 光标选中指定的类,查看继承树结构:ctrl + t
// * 16.复制代码: ctrl + c
// * 17.撤销: ctrl + z
// * 18.反撤销: ctrl + y
// * 19.剪切:ctrl + x
// * 20.粘贴:ctrl + v
// * 21.保存: ctrl + s
// * 22.全选:ctrl + a
// 格式化代码: ctrl + shift + f
// * 24.选中数行,整体往后移动:tab
// * 25.选中数行,整体往前移动:shift + tab
// 在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl + o
// 批量修改指定的变量名、方法名、类名等:alt + shift + r
// 选中的结构的大小写的切换:变成大写: ctrl + shift + x
// 选中的结构的大小写的切换:变成小写:ctrl + shift + y
final double PI = 3.14; //常量必大写
// 调出生成getter/setter/构造器等结构: alt + shift + s
// 显示当前选择资源(工程 or 文件)的属性:alt + enter ---看属性
// 快速查找:参照选中的Word快速定位到下一个 :ctrl + k
// 关闭所有的窗口:ctrl + shift + w
// 查看指定的结构使用过的地方:ctrl + alt + g
// 查找与替换:ctrl + f
// 最大化当前的View:ctrl + m
// 直接定位到当前行的首位:home
// 直接定位到当前行的末位:end
}
}
/**
*
* @Description
* @author tyl Email:tyl202061@gmail.com
* @version
* @date 2023年3月15日下午6:57:07
*
*/
class Users{
private int id;
private String name;
public int getId() {
return id;
}
/**
*
* @Description
* @author tyl
* @date 2023年3月15日下午6:57:39
* @param id
*/
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}