对象的特点
类和对象的关系
类:类是抽象的,概念上的东西
对象:是实实在在的个体
对象时由类派生出来的
类和对象的创建和操作分为那三步
创建类
类的实例化
调用对象的结构,使用 对象.属性、对象.方法
面向过程和面向对象
面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做
实现一个类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class javaobject01 { public static void main (String[] args) { Person per = new Person(); per.name = "张三" ; per.age = 18 ; per.gender = '男' ; per.eat(); per.skip("中文" ); per.sleep(); per.info(); } } class Person { String name; char gender; int age; public void eat () { System.out.println("人可以吃饭" ); } public void sleep () { System.out.println("人可以睡觉" ); } public void skip (String language) { System.out.println("说的语言是:" + language); } public void info () { System.out.println(name+"今年" + age + "岁,性别为:" + gender); } }
一个类可以实例化出多个对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class javaobject01 { public static void main (String[] args) { Person p1 = new Person(); p1.name = "张三" ; p1.age = 18 ; p1.gender = '男' ; p1.eat(); p1.skip("中文" ); p1.sleep(); p1.info(); Person p2 = new Person(); p2.name = "李四" ; System.out.println(p2.name); } } class Person { String name; char gender; int age; public void eat () { System.out.println("人可以吃饭" ); } public void sleep () { System.out.println("人可以睡觉" ); } public void skip (String language) { System.out.println("说的语言是:" + language); } public void info () { System.out.println(name+"今年" + age + "岁,性别为:" + gender); } }
两个对象指向堆空间中的同一地址 1 2 3 4 5 6 7 8 9 10 Person p3 = p1; System.out.println(p3); System.out.println(p3.name); p3.name = "王五" ; System.out.println(p1.name);
属性和局部变量的对比
相同点
声明方式相同:变量类型 变量名 = 变量值;
先声明,后使用
变量都有其对应的作用域
不同点
再类中声明的位置不同
属性声明在类的一对 {} 中
局部变量:声明在方法中、方法形参、代码块、构造器形参、构造器内部
权限修饰符不同
属性:在声明属性时可以指明其权限,使用权限修饰符
常用的权限修饰符有:public、private、缺省(不使用修饰符默认为此)、protected
局部变量:不能使用权限修饰符
默认初始化值不同
属性:有默认的初始值,在使用属性时可以不事先赋值即可直接使用它的默认值
局部变量:没有初始值,使用局部变量时必须先赋值才能使用。形参在调用方法时必须对形参赋值
在内存中定义的位置不同
1 2 3 4 5 6 7 8 9 10 11 12 13 class User { String name; int age; boolean isMain; public void talk (int age) { String name; name = "李四" ; } }
类中的方法定义 定义方法时,如果方法没有返回值,则使用 void,如果有返回值,应该声明返回数据的类型
声明的方式
无返回值
1 2 3 public void 方法名(){ 方法体 }
有返回值
1 2 3 public 返回的数据类型 方法名(){ return 返回值 }
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class javamethods03 { public static void main (String[] args) { User2 u = new User2(); u.eat(); u.sleep(2 ); System.out.println(u.getName()); System.out.println(u.add(2 , 5 )); } } class User2 { public void eat () { System.out.println("吃饭" ); } public void sleep (int hour) { System.out.println("一共睡了" + hour + "个小时" ); } public String getName () { return "爸爸的爸爸叫爷爷" ; } public int add (int a,int b) { return a + b; } }
return 关键字的使用
使用范围:使用在方法体中
作用
结束方法执行
针对于有返回值的方法,使用 return 返回想要返回的数据
注意点:return 后面不能有执行语句
理解万事万物皆对象
在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
Scanner,String 等
文件:File
网络资源:URL
涉及到Java语言与前端HTML,数据库等交互时,前后端的结构在Java层面交互时,都体现为类、对象
匿名对象的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class nimingobject { public static void main (String[] args) { new Phone().sendEmail(); new Phone().playGame(); new PhoneMarket().showPhoneInfo(new Phone());; } } class PhoneMarket { public void showPhoneInfo (Phone phone) { phone.sendEmail(); phone.playGame(); } } class Phone { double price; public void sendEmail () { System.out.println("发送邮件" ); } public void playGame () { System.out.println("打游戏" ); } }
方法重载
定义:在同一个类中,允许存在多个同名的方法。只要它们的参数列表不同即可
简单的理解为 两同一不同
同一个类
同一个方法名
参数列表不同、参数类型不同、参数个数不同
举例:例如在 Scanner 类中存在多个 sort 方法,每个 sort 方法接收的参数类型都不相同
判断是否是重载
和方法的权限修饰符、返回值类型、形参变量名称、方法体都没有关系
在调用重载方法时,如何确认使用的是那一个方法
方法名 —> 参数列表
在编写代码是就已经确定了使用的是那一个重载方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class FunctionResove04 { public static void main (String[] args) { Print p = new Print(); p.getSum(2 ); p.getSun(5 , 7 ); p.getSum(5 , 7 ); } } class Print { public void getSum (int i, int j) { System.out.println(i + j); } public void getSun (double i, double j) { System.out.println(i + j + 10 ); } public void getSum (int a) { System.out.println(a); } }
可变个数形参 使用方式
数据类型 … 变量名
1 2 3 4 5 public void functionName (String ... args) { for (int i = 0 ; i < args.length; i++){ System.out.println(args[i]); } }
知识点:
可变个数形参的个数没有数量限制,也可以是0个
可变个数形参的方法可同类中的同方法名不同参数列表之间的方法构成重载
可变个数形参的方法和本类中数据类型相同的数组为形参的方法之间不能同时存在,二者在本质上是相同的
可变个数形参和固定个数的形参可以同时存在,但是可变个数形参必须声明在最后,否则会报错
可以像遍历数据一样遍历可变数量的形参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.util.Arrays;public class VariableForman { public static void main (String[] args) { VariableForman v = new VariableForman(); v.show(5 ); v.show(5 , 5 , 6 , 7 ); v.show("Hello" , 1 ,2 ,3 ,4 ,5 ); v.show(); v.show("Hello" );; } public void show (int i) { System.out.println("one int" ); } public void show (int ... args) { System.out.println("可变个数形参方法" ); for (int i = 0 ; i < args.length; i++) { System.out.println(args[i]); } } public void show (String i, int ... args) { System.out.println("固定的参数为" + i); System.out.println(Arrays.toString(args)); } }
补充:
当我们用 int ... args
去接收多个参数时,可以传递过来 int 类型的数组,也可以传递过来多个 int 类型的数据。但是当方法明确的定义了接收的是一个数组类型的数据,则必须传递一个数组,不能传递多个数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class ArgumentTest { public static void main (String[] args) { Sub s = new Sub(); s.add(1 , 2 , 3 , 4 ); s.add(1 , new int [] {2 ,3 ,4 }); s.show(1 , new int [] {2 ,3 ,4 }); } } class Sub { public void add (int i, int ...arg) { System.out.println("Sub1" ); } public void show (int i, int [] arg) { System.out.println("Show" ); } }
值传递机制 关于形参的变量赋值
如果变量是基本数据类型,此时赋的值是变量所保存的数据值
如果变量是引用数据类型,此时赋的值是变量所保存的地址值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ValueTest05 { public static void main (String[] args) { Data data = new Data(); ValueTest05 test = new ValueTest05(); test.exChange(data); System.out.println(data.m + "," + data.n); } public void exChange (Data data) { int temp = data.m; data.m = data.n; data.n = temp; } } class Data { int m = 10 ; int n = 20 ; }
将对象作为参数传递 1 2 3 4 5 6 7 8 9 10 public class Circle02 { double redius; public double findArea () { return Math.PI * redius * redius; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Circle02Test { public static void main (String[] args) { Circle02Test test = new Circle02Test(); Circle02 c = new Circle02(); test.printAreas(c,5 ); System.out.println("now redius is " + c.redius); } public void printAreas (Circle02 c,int item) { System.out.println("Redius\t\tArea" ); for (int i = 1 ; i <= item; i++) { c.redius = i; System.out.println(c.redius + "\t\t" + c.findArea()); } c.redius = item + 1 ; } }
递归方法
方法递归包含了一种隐式的循环,他会重复执行某一段代码,但这种重复执行无需循环控制
递归一定要向一直的放行递归,否则这种递归就变成了无穷递归,类似于死循环
1 2 3 4 5 6 7 8 public int getSum (int n) { if (n == 1 ) { return 1 ; }else { return n - getSum(n - 1 ); } }
分析下面代码的内存解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class NeiCun { public static void main (String[] args) { NeiCun test = new NeiCun(); test.first(); } public void first () { int i = 5 ; Value v = new Value(); v.i = 25 ; second(v,i); System.out.println(v.i); } public void second (Value v,int i) { i = 0 ; v.i = 20 ; Value val = new Value(); v = val; System.out.println(v.i + " " + i); } } class Value { int i = 15 ; }
封装性的引入 我们在修改类中的某个属性时,想对这个属性作出一些限制条件。比如我们设置 age 时不能设置负数以及0,那么应该怎么做呢?
给属性添加权限修饰符
private 私有属性,只能在类中使用,类外部不可见
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class AniamTest01 { public static void main (String[] args) { Dog d = new Dog(); d.name = "阿黄" ; d.setAge(5 ); d.show(); } } class Dog { String name; private int age; public void setAge (int i) { if (i <= 0 ) { age = 1 ; }else { age = i; } } public int getAge () { return age; } public void show () { System.out.println("狗狗的名字是 " + name + ",今年" + age + "岁了" ); } }
封装性的体现
我们将属性设为私有属性(private)的同时,提供了公共的(public)设置方法和读取方法
我们将类中的方法设置为私有的,只在类中内部使用
单例模式
我们的程序设计追求 “高内聚,低耦合”
高内聚:类的内部数据细节操作自己完成,不允许外部干涉
低耦合:仅对外暴露少量的方法用于使用
我们封装就是想要隐藏对象的内部复杂性,只对外公开简单的接口,便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,吧该隐藏的隐藏起来,该暴露的暴露出来,这就是封装的思想
封装性的体现,需要权限修饰符来配合
四种权限修饰符 权限范围从小到大排序
修饰符
类内部
同一个包
不同包的子类
同一个工程
private(私有的)
Yes
缺省
Yes
Yes
protected(受保护的)
Yes
Yes
Yes
public(公共的)
Yes
Yes
Yes
Yes
对于 class 的权限修饰符只能使用 public 和 缺省
public 修饰的类在任意地方都可以被访问到
缺省的 class 只能被同一个包下的内部类访问
封装性的练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Proson { private int age; public void setAge (int i) { if (i > 0 && i <= 150 ) { age = i; } else { throw new RuntimeException("设置的值有误" ); } } public int getAge () { return age; } }
使用封装好的方法
1 2 3 4 5 6 7 8 public class ProsonTest { public static void main (String[] args) { Proson p = new Proson(); p.setAge(18 ); System.out.println(p.getAge()); } }
构造器基本理解 作用:
说明
如果没有显示的定义类的构造器的话,则系统会默认定义一个空参的构造器
定义构造器的格式:权限修饰符 类名(形参列表){ }
一个类中定义多个构造器就构成了方法重载
如果类中显示的定义了类的构造器,则系统不再提供默认的空参构造器
一个类中至少会有一个构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ConstructorTest02 { public static void main (String[] args) { Proson p = new Proson(15 ); } } class Proson { int age; public Proson () { System.out.println("new 一个构造器的同时调用此方法" ); } public Proson (int i) { age = i; System.out.println("携带有参数的构造器" + age); } }
构造器练习
在 Person 类中添加一个构造器,利用构造器设置所以人的 age 初始值都是 18
修改上题中类和构造器,增加 name 属性,使得在每次创建 Person 对象时同时设置 age 属性和 name 属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class Person { private int age; private String name; public Person () { age = 18 ; } public Person (String n, int a) { name = n; age = a; } public void setAge (int i) { if (i > 0 && i <= 150 ) { age = i; } else { throw new RuntimeException("设置的值有误" ); } } public int getAge () { return age; } public void setName (String name) { name = name; } public String getName () { return name; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class PersonTest { public static void main (String[] args) { Person p = new Person(); System.out.println(p.getAge()); p.setAge(24 ); System.out.println(p.getAge()); Person p2 = new Person("张三" ,21 ); System.out.println(p2.getName()); System.out.println(p2.getAge()); } }
属性赋值的过程 按先后顺序排列
默认初始化
显示初始化
构造器赋值
使用 对象.属性 赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class SetValue03 { public static void main (String[] args) { User u = new User(); System.out.println(u.getAge()); User u2 = new User(25 ); System.out.println(u2.getAge()); u2.setAge(35 ); System.out.println(u2.getAge()); } } class User { private int age; public User () { } public User (int i) { age = i; } public void setAge (int i) { age = i; } public int getAge () { return age; } }
JavaBean 的使用 JavaBean是使用Java语言编写的可重用组件,所谓的JavaBean,是指符合下列标准的类
类是公共的
有一个无参的构造器
有属性,并且每个属性有对应的 get set 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Customer { int age; String name; public Customer () { } public void setAge (int i) { age = i; } public int getAge () { return age; } public void setName (String n) { name = n; } public String getName () { return name; } }
UML类图
上图转换为代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Account { private double balance; public Account (double init,double balance) { } public double getBalance () { return 0.0 } public void deposit (double amt) { } public void withdraw (double amt) { } }
this关键字调用属性和方法 this关键字的使用:
this修饰属性和方法
this可以理解为当前或者当前正在创建的对象
在类的方法中,我们可以使用 this.属性 this.方法 的形式来调用当前类中的属性和方法,但是我们通常情况我们可以省略 this 的使用,但是在方法中,我们的形参和属性名相同时,我们要在属性签名添加一个 this来区分那个是我们类中的属性,那个是形参
1 2 3 4 5 6 7 8 9 10 11 class User2 { private String name; public void setName (String name) { this .name = name; } public String getName () { return name; } }
this调用构造器
我们在类的构造器中可以显示的使用 this(形参列表)
来调用这个类中其他指定构造器
构造器中不能通过 this(形参列表)
来调自己,和调用的构造器之间也不能形成互相调用的结果
如果一个类中有 n 个构造器,则最多有 n-1 个构造器中使用 this(形参列表)
规定this(形参列表)
必须声明在当亲构造器的首行
一个构造器中最多只能声明一个 this(形参列表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class ConstructorThis06 { public static void main (String[] args) { User3 u = new User3("张三" ,18 ); System.out.println(u.age); System.out.println(u.name); } } class User3 { int age; String name; public User3 () { System.out.println("空参构造器执行的多行代码...." ); } public User3 (int age) { this (); this .age = age; } public User3 (String name,int age) { this (age); this .name = name; } }
阶段练习,this当做参数传递 this表示当前的整个类,作为参数传递时表示将当前的类传递给了另外一个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Boy { private String name; private int age; public Boy () { } public Boy (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 (Gril gril) { System.out.println("我想娶" + gril.getName()); } public void shout () { if (this .age > 22 ) { System.out.println("可以进行登记" ); }else { System.out.println("多谈恋爱" ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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("我想嫁给" + boy.getName()); boy.marry(this ); } public int compare (Gril gril) { return this .age - gril.getAge(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class BoyGrilTest { public static void main (String[] args) { Boy boy1 = new Boy("罗密欧" ,21 ); Gril gril1 = new Gril("朱丽叶" ,19 ); boy1.marry(gril1); gril1.marry(boy1); Gril gril2 = new Gril("祝英台" ,19 ); int comper = gril1.compare(gril2); if (comper > 0 ) { System.out.println(gril1.getName() + "大" ); }else if (comper < 0 ) { System.out.println(gril2.getName() + "大" ); }else { System.out.println("一样大" ); } } }
数组动态扩容 练习二代码地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void resize (int size) { Customer[] tempCus = this .customers; this .customers = new Customer[size]; for (int i = 0 ; i < tempCus.length; i++) { this .customers[i] = tempCus[i]; } }
1 2 3 4 5 6 7 8 9 10 11 12 public void addCustomer (String name) { if (this .customerLength == this .customers.length) { resize(this .customerLength + 10 ); } Customer cust = new Customer(name); this .customers[this .customerLength++] = cust; }
package 关键字的使用
为了更好的管理我们项目中的多个类,提供了包的概念
应该在源文件的首行使用 package 声明类或者方法所属的包
包属于标识符,应该遵循标识符命名规范(xxxyyyzz),应该做到见名知意
每 “ . ” 一次,就代表一层文件目录
同一个包下,不能命名同名的类,在不同的包下可以命名同名类
1 2 3 4 5 6 7 8 package com.songzx.day02Java; public class PackageTest07 { public static void main (String[] args) { } }
MVC 设计模式(初识) MVC是常用的设计模式之一,将整个程序分为三个层次:
视图模型层(view)
控制器层(controller)
数据模型层(modal)
这种将程序的输入,数据处理,以及数据展示分离开来的设计模式,是程序结构变得灵活而清晰,同时也描述了各个对象之间的通信方式,降低了程序的耦合性
import 关键字使用
在源文件中可以显示的使用 import 关键字导入指定包下面的类、接口
声明的位置在包声明和类声明之间
如果需要导入多个结构,可以并列的导入
可以使用 “XXX*” 的方式导入 XXX 包下面的所有结构
如果使用的是 java.lang 包下面定义的类或者接口,则可以不用导入 java.lang
如果使用的接口或者类是在本包下定义的,则不用导入
在源文件中,如果使用了不同包下面的同名类,则至少有一个类需要使用全类名的方式来使用
使用 “ XXX* ” 的方式调用了 XXX 下面的子包下面的结构,仍然需要使用 import 来导入
import static : 导入指定类或接口中的静态结构:属性、方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import com.songzx.javaobject.ArrayUtil;import com.songzx.javaobject.*;import com.songzx.exer01.Account;public class ImportTest08 { public static void main (String[] args) { ArrayUtil au = new ArrayUtil(); javaobject01 obj01 = new javaobject01(); SetValue03 setval = new SetValue03(); Account a01 = new Account(); com.songzx.exer02.Account a02 = new com.songzx.exer02.Account(0 ); } }