面向过程(POP:Procedure Oriented Programming),强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象(OOP:Object Oriented Programming ),将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
封装(Encapsulation) 、继承(Inheritance)、多态(Polymorphism)
(1)根据问题需要,选择问题所针对的现实世界中的实体。
(2)从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
(3)把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
(4)将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
(1)类:类是对一类事物的描述,是抽象的、概念上的定义
(2)对象:对象是实际存在的该类事物的每个个体,因而也称为实例(instance)。
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类
(1)定义类(考虑修饰符、类名)
(2) 编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
(3) 编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
(1)定义格式: 数据类型 变量名 = 变量值
(2)先声明,后使用
(3)变量都有其相应的作用域
属性:直接定义在类的一对{}内。
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量。
属性:可以在声明属性时,指明其权限,使用权限修饰符。(public、private、protected、缺省)
局部变量:不可以使用权限修饰符。
属性:类的属性,根据其类型,都有默认初始化值。[引用数据类型(类、数组、接口):null]
局部变量:没有默认初始化值。
属性:加载到堆空间中。(非static)
局部变量:加载到栈空间。
方法的使用中,可以调用当前类的属性或方法
/**
* 功能:设计类并创建对象,调用其中的属性和方法
* @author wuzec
*
*/
public class PersonTest {
public static void main(String[] args) {
//创建Person对象
Person p1 = new Person();
//调用属性
p1.age = 10;
p1.isMale = true;
p1.name="Wu";
System.out.println(p1.name);
//调用方法
p1.eat();
p1.sleep();
p1.talk("Chinese");
}
}
class Person{
//属性
String name;
int age;
boolean isMale;
//方法
public void sleep() {
System.out.println("sleeping");
}
public void eat() {
System.out.println("eating");
}
public void talk(String language) {
System.out.println("talk using " + language);
}
}
堆(Heap):此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。所有的对象实例以及数组都要在堆上分配。
栈(stack):指的是虚拟机栈,用于存储局部变量等。 局部变量表存放了编译期可知长度的各种基本数据类型、对象引用。 方法执行完,自动释放。
方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态 变量、即时编译器编译后的代码等数据。
/**
* 功能:内存解析的一个小例子
* @author wuzec
*
*/
public class PersonTest {
public static void main(String[] args) {
//创建Person对象
Person p1 = new Person();
//调用属性
p1.age = 10;
p1.isMale = true;
p1.name="Wu";
System.out.println(p1.name);
Person p2 = new Person();
p2 = p1; //p1对象的指针,传到p2中,p1与p2指向同一个区域
System.out.println(p2.name); //Wu
System.out.println(p2.age);//10
System.out.println(p2.IsMale);//true
}
}
class Person{
String name;
int age;
boolean isMale;
public void sleep() {
System.out.println("sleeping");
}
public void eat() {
System.out.println("eating");
}
public void talk(String language) {
System.out.println("talk using " + language);
}
}
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
“两同一不同”:同一个类、方法名相同;参数列表不同,参数个数不同,参数类型不同。
判断是否重载与方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系。
/**
* 功能:测试方法重载
* @author wuzec
*
*/
public class OverloadTest {
public static void main(String[] args) {
OverloadTest t1 = new OverloadTest();
t1.getSum(1, 1); //1
t1.getSum(1.2, 2.2); //2
t1.getSum(1, 2, 0.1); //3
t1.getSum(1, 2, 3); //4
}
public void getSum(int a, int b) {
System.out.println("1");
}
public void getSum(double a, double b) {
System.out.println("2");
}
public void getSum(int a, int b, double c) {
System.out.println("3");
}
public int getSum(int a, int b, int c) {
System.out.println("4");
return 0;
}
}
可变个数形参的格式:数据类型 … 变量名
当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,n个
可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
可变个数形参在方法的形参中,必须声明在末尾。
可变个数形参在方法的形参中,最多只能声明一个可变形参。
/**
* 功能:测试可变行参的方法
* @author wuzec
*
*/
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest t1 = new MethodArgsTest();
t1.show(); //1
t1.show("hhah"); //2
t1.show("hahah", "world", "nini"); //3
t1.show(1, "hello","world"); //4
}
public void show() {
System.out.println("1");
}
public void show(String s) {
System.out.println("2");
}
//jdk 5.0 之后的新特性
public void show(String ... strs) {
System.out.println("3: show(String .. str)");
//strs可以看成数组的处理方式
for(int i=0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
// 在jdk 5.0之前使用此方式来进行可变参数方法
// public void show(String[] args) {
//
// }
//可变形参必须放在参数列表的最后,并且只能有一个
public void show(int a, String ...strs) {
System.out.println("4");
}
}
形参:方法声明时的参数
实参:方法调用时实际传给形参的参数值
Java里方法的参数传递方式只有一种:值传递。 即将实际参数值的副本 (复制品)传入方法内,而参数本身不受影响。
如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
/**
* 功能:测试基本数据类型和引用数据类型变量赋值的本质
* @author wuzec
*
*/
public class ValueTransferTest {
public static void main(String[] args) {
System.out.println("************基本数据类型******************");
int m = 10;
int n = m; //n变量在栈中 存储的为m变量中的值
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 10
n = 20;
System.out.println("m = " + m + ", n = " + n);//m = 10, n = 20
System.out.println("************引用数据类型******************");
Item i1 = new Item();
i1.id = 100;
Item i2 = new Item();
i2 = i1; //i2变量接收的是i1对象所指向的地址值,所以他们在内存中的位置是一样的
System.out.println("i1.id = " + i1.id + ", i2.id = " + i2.id);//i1.id = 100, i2.id = 100
i2.id = 200;
System.out.println("i1.id = " + i1.id + ", i2.id = " + i2.id);//i1.id = 200, i2.id = 200
}
}
class Item{
int id;
}
值传递机制:
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
/**
* 功能:测试值传递机制
* @author wuzec
*
*/
public class ValueTransferTest1 {
public static void main(String[] args) {
System.out.println("********基本数据类型**********");
int m = 10;
int n = 20;
System.out.println("m = " + m + ", n = " + n );//m = 10, n = 20
ValueTransferTest1 test = new ValueTransferTest1();
test.swap1(m, n);
System.out.println("m = " + m + ", n = " + n );//m = 10, n = 20
System.out.println("********引用数据类型**********");
Data d1 = new Data();
d1.m = 10;
d1.n = 20;
System.out.println("m = " + d1.m + ",n = " + d1.n);//m = 10,n = 20
test.swap2(d1);
System.out.println("m = " + d1.m + ",n = " + d1.n);//m = 20,n = 10
}
void swap1(int i, int j) {
int temp = i;
i = j;
j = temp;
}
void swap2(Data d1) {
int temp = d1.m;
d1.m = d1.n;
d1.n = temp;
}
}
class Data{
int m;
int n;
}
一个方法体内调用它自身。
在进行程序设计中,要遵循“高内聚,低耦合”的原则。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
Java中通过将数据声明为私有的(private),再提供公共的(public) 方法:getXxx()和setXxx()实现对该属性的操作
/**
* 功能:get方法与set方法
* @author wuzec
*
*/
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.setName("tiger");
a.setAge(15);
System.out.println("名字为:" + a.getName());
System.out.println("年龄为" + a.getAge() );
}
}
class Animal{
private String name;
private int age;
//get set方法
public String getName(){
return name;
}
public void setName(String s){
name = s;
}
public int getAge() {
return age;
}
public void setAge(int a) {
age = a;
}
}
4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类。
修饰类只能用:缺省、public
创建对象,给对象进行初始化
隐藏式的无参构造器(系统默认提供)
显示定义一个多个构造器(有参、无参)
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符 类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器。
/**
* 功能:构造器的使用
* @author wuzec
*
*/
public class PersonATest {
public static void main(String[] args) {
PersonA p1 = new PersonA();//PersonA()......
PersonA p2 = new PersonA("uzi");
PersonA p3 = new PersonA(12);
PersonA p4 = new PersonA("uzi", 12);
p1.show();// name = null, age = 0
p2.show();// name = uzi, age = 0
p3.show();// name = null, age = 12
p4.show();// name = uzi, age = 12
}
}
class PersonA{
//属性
String name;
int age;
//构造器
public PersonA(){
System.out.println("PersonA()......");
}
public PersonA(String str) {
name = str;
}
public PersonA(int a) {
age = a;
}
public PersonA(String str, int a) {
name = str;
age = a;
}
//方法
public void eat() {
System.out.println("eating....");
}
public void show() {
System.out.println(" name = " + name + ", age = " + age);
}
}
this关键字可以修饰属性、方法、构造器。
this理解为:当前对象 或 当前正在创建的对象。
在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式使用"this.变量"的方式,表明此变量是属性,而非形参。
/**
* 功能:this关键字的修饰属性与方法
* @author wuzec
*
*/
public class PersonBTest {
public static void main(String[] args) {
PersonB p1 = new PersonB();
p1.setName("张三");
p1.setAge(15);
System.out.println("p1 的形名为 "+ p1.getName() + ", 年龄为 "+ p1.getAge());
p1.eat();
}
}
class PersonB{
//属性
String name;
int age;
//构造器
public PersonB() {
}
public PersonB(String name, int age){
this.name = name;
this.age = age;
}
//set、get方法
public void setName(String name) {
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 study() {
System.out.println("studying.....");
}
public void eat() {
System.out.println("eating.....");
this.study();
}
}
在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器。
构造器中不能通过"this(形参列表)“方式调用自己。
如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)”。
规定:"this(形参列表)“必须声明在当前构造器的首行。
构造器内部,最多只能声明一个"this(形参列表)”,用来调用其他的构造器。
class PersonC{
String name;
int age;
public PersonC(){
}
public PersonC(int age){
this.age = age;
}
public PersonC(int age, String name){
this(age);
this.name = name;
}
}
public class Person {
String name;
int age;
int sex;
public void study(){
System.out.println("studying");
}
public void showAge() {
System.out.println(age);
}
public int addAge(int i){
age = age + i;
return age;
}
}
PersonTest.java:
public class PersonTest {
public static void main(String[] args) {
Person p1= new Person();
p1.name = "Tom";
p1.age = 10;
p1.sex = 1;
p1.study();
p1.showAge();
p1.addAge(5);
p1.showAge();
}
}
package newquestion;
/**
* 功能:ex2 解法
* @author wuzec
*
*/
public class StudentTest {
public static void main(String[] args) {
Student[] stus = new Student[20];
for(int i = 0; i < stus.length; i++) {
//给数组元素赋值
stus[i] = new Student();
//给Student对象的属性赋值
stus[i].number = (i + 1);
//年级[1,6]
//求[n,m]随机数 Math.random()*(m-n+1)+1
stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
stus[i].score = (int)(Math.random() * (100 - 0 + 1) + 1);
}
//遍历数组
for(int i = 0; i < stus.length; i++) {
System.out.println(stus[i].info());
}
System.out.println();
//打印三年级的学生信息
for(int i = 0; i < stus.length; i++) {
if(stus[i].state == 3) {
System.out.println(stus[i].number + "学生的三年级,成绩为" + stus[i].score);
}
}
//按照成绩进行排序
for(int i = 0; i < stus.length - 1; i++) {
for(int j = 0; j<stus.length - i - 1; j++) {
if(stus[j].score > stus[j + 1].score) {
Student temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
System.out.println();
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 newquestion;
public class Account {
private int id;//帐号
private double balance;//余额
private double annuallnterestRate;//年利率
public Account(int id, double balance,double annuallnterestRate) {
this.id = id;
this.balance = balance;
this.annuallnterestRate = annuallnterestRate;
}
public int getId() {
return this.id;
}
public double getBalance() {
return this.balance;
}
public double getAnnuallnterestRate() {
return this.annuallnterestRate;
}
public void setId(int id) {
this.id = id;
}
public void setBalance(double balance) {
this.balance = balance;
}
public void setAnnuallnterestRate(double annuallnterestRate) {
this.annuallnterestRate = annuallnterestRate;
}
//取钱
public void withdraw(double amount) {
if(amount < balance) {
balance = balance - amount;
System.out.println("成功取出 " + amount +"元, 账户余额为 " + balance + "元");
}
else {
System.out.println("账户余额不足");
}
}
//存钱
public void deposit(double amount) {
balance = balance + amount;
System.out.println("成功存入 "+ amount + "元,账户余额为" + balance + "元");
}
}
Customer.java:
package newquestion;
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 String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public Account getAccount(){
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
}
AccAndCusTest.java:
package newquestion;
public class AccAndCustTest {
public static void main(String[] args) {
Customer c1 = new Customer("Jana","Smith");
Account a1 = new Account(1000,2000,0.0123);
c1.setAccount(a1);
c1.getAccount().deposit(100);
c1.getAccount().withdraw(960);
c1.getAccount().withdraw(2000);
System.out.println("Customer " + "["+ c1.getFirstName() + c1.getLastName() + "]"
+ "has a account: id is " + c1.getAccount().getId() + " annualInterestRate is "
+ c1.getAccount().getAnnuallnterestRate()*100 + "%, balance is "
+ c1.getAccount().getBalance());
}
}
package ex2;
public class Account {
private double balance;
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return this.balance;
}
//存款
public void deposit(double amt) {
if(amt >0) {
balance += amt;
System.out.println("存钱成功,余额为" + balance );
}
}
//取款
public void withdraw(double amt) {
if(amt > balance) {
System.out.println("取款失败,余额不足");
}
else {
balance -= amt;
System.out.println("取款成功,余额为"+balance);
}
}
}
Customer.java:
package ex2;
public class Customer {
private String firstName;
private String lastName;
private Account account;
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
Bank.java:
package ex2;
public class Bank {
private Customer[] customers;// 存放多个数组
private int numberOfCustomer;//记录客户的个数
public Bank() {
customers = new Customer[10];
}
//添加用户
public void addCustomer(String f, String l) {
Customer cust = new Customer(f,l);
customers[numberOfCustomer++] = cust;
}
//获取用户个数
public int getNumOfCustomers() {
return numberOfCustomer;
}
//获取指定位置上的用户
public Customer getCustomer(int index) {
if(index>=0 && index < numberOfCustomer){
return customers[index];
}
return null;
}
}
BankTest.java:
package ex2;
public class BankTest {
public static void main(String[] args) {
Bank bank = new Bank();
bank.addCustomer("Jane", "Smith");
//连续操作
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());
}
}
参考资料:
[1]尚硅谷宋康红java基础教程