文章目录
Java_面向对象编程
基本概念
- 万物皆对象。
- 面向对象指以属性和行为的观点去分析现实生活中的事物。
- 面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言进行表达的过程。
- 面向对象的思想精髓(封装、继承、多态)
面向过程(POP) 与 面向对象(OOP)
- 面向过程编程,强调的是功能行为,以函数为最小单位,考虑怎么做。
- 面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
- 面向对象更加强调运用人类在日常的思维逻辑中采用的思想方法与原则,如抽象、分类、继承、聚合、多态等
- 面向对象的三大特征:
封装 (Encapsulation),继承 (Inheritance),多态 (Polymorphism)
面向对象分析方法分析问题的思路和步骤
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实体中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构造成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
Java_类和对象的概念
- 对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空间中的一块存储区域。
- 对象是实际存在的该类事物的每个个体,因而也称为实例
(instance)
。 - 类是对一类事物的描述,是抽象的,概念上的定义,比如人,动物就是抽象的概念,类简单来就是“分类”,是对具有相同特征和行为的多个对象共性的抽象描述,比如人,动物就是抽象的概念
- 类在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性的成员变量以及描述行为的成员方法。
- 类是用于构建对象的模板,对象的数据结构由定义它的类来决定。
- 对象的数据模型,用于描述对象的数据,又被称为对象的属性,或者对象的成员变量
- 对象的行为模型,用于描述对象能够做什么事情,又称为对象的方法
- 类属性作为该类各个对象之间共享的变量。
类属性、类方法的设计思想
-
在设计类时,分析哪些属性不因对象的不同而改变,将这些属性设置为类属性。与类属性相应的方法设置为类方法。
-
如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
// 类变量(类属性)由该类的所有实例共享 public class Person { private int id; public static int total = 0; public Person() { total++; id = total; } public static void main(String args[]){ Person Tom=new Person(); Tom.id=0; total=100; // 不用创建对象就可以访问静态成员 } } public class StaticDemo { public static void main(String args[]) { Person.total = 100; // 不用创建对象就可以访问静态成员 //访问方式:类名.类属性,类名.类方法 System.out.println(Person.total); Person c = new Person(); System.out.println(c.total); //输出101 } }
Java_类的语法格式
-
类的定义
class 类名 { 类体; } // 通常情况下,当类名由多个单词组成时,要求每个单词首字母都要大写 class Person{ }
-
成员变量的定义
class 类名 { 数据类型 成员变量名 = 初始值; } // 当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首字母大写 class Person { private int age ; //声明私有变量 age public void showAge(int i) { //声明方法showAge( ) age = i; } }
-
对象的创建:
- 当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个过程叫做类的实例化
- 创建对象的本质就是在内存空间的堆区申请一块存储区域,用于存放该对象独有特征信息
// 当类名由多个单词组成时,要求每个单词首字母都要大写。 创建方式:new 类名(); // 当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首字母大写 class Person { String name; } // 创建对象语法: 类名 对象名 = new 类名(); Person p = new Person(); // 使用“对象名.对象成员”的方式访问对象成员(包括属性和方法) p.name = "张三";
- 如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰
public class Zoo { public static void main(String args[]) { Animal xb = new Animal(); Animal xh = new Animal(); xb.legs = 4; xh.legs = 0; System.out.println(xb.legs); // 4 System.out.println(xh.legs); // 0 xb.legs = 2; System.out.println(xb.legs); // 2 System.out.println(xh.legs); // 0 } }
-
引用的定义:
- 使用引用数据类型定义的变量叫做引用型变量,简称为"引用"
- 引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问
Person p = new Person(); p.name = "张飞"; System.out.println(p.name);
-
成员变量的初始值:对象创建后,其成员变量可以按照默认的方式初始化,具体规则如下:
成员变量的类型 默认初始值 数值类型:byte、short、int、long、float、double、char 0 boolean型 false 引用类型 null
PS:类的访问机制
- 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。
(例外:static方法访问非static,编译不通过。)
- 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。
Java_成员方法
- 成员方法即写在类内部的方法,
- 没有对象的实例时,可以用
类名.方法名()
的形式访问由static
修饰的类方法。 - 在
static方法
内部只能访问类的static修饰的属性或方法
,不能访问类的非static的结构
。 - static修饰的方法不能被重写
class 类名 {
返回值类型 成员方法名(形参列表) {
成员方法体;
}
}
// 样例如:
public void walk(){
System.out.println("每个人都会走路");
}
public String say(){
return "人的名字是:" +name+ ",年龄是:"+age+",地址是:"+address;
}
// 当成员方法名由多个单词组成时,要求从第二个单词起每个单词的首字母大写
public String personRun(String name){
return "我是:"+name+",跑步去了";
}
class Person {
private int id;
private static int total = 0;
public static int getTotalPerson() {
//id++; //非法
return total;
}
public Person() {
total++;
id = total;
}
}
public class PersonTest {
public static void main(String[] args) {
System.out.println("Number of total is " + Person.getTotalPerson());
//没有创建对象也可以访问静态方法
Person p1 = new Person();
System.out.println( "Number of total is "+ Person.getTotalPerson());
}
}
注意:因为不需要实例就可以访问static方法,因此static方法内部不能有this和super。
class Person {
private int id;
private static int total = 0;
public static void setTotalPerson(int total){
this.total=total; //非法,在static方法中不能有this,也不能有super
}
public Person() {
total++;
id = total;
}
}
public class PersonTest {
public static void main(String[] args) {
Person.setTotalPerson(3);
}
}
返回值类型
- 返回值主要指从方法体内返回到方法体外的数据内容。
- 返回值类型主要指返回值的数据类型,可以是基本数据类型,也可以是引用数据类型
- 当返回的数据内容是66时,则返回值类型写 int 即可
- 在方法体中使用return关键字可以返回具体的数据内容并结束当前方法。
- 当该方法不需要返回任何数据内容时,则返回值类型写void即可。
形参列表详解
-
形式参数主要用于将方法体外的数据内容带入到方法体内部
-
形式参数列表主要指多个形式参数组成的列表,
// 语法格式如:数据类型 形参变量名1, 数据类型 形参变量名2, ... public String personRun(String name1,String name2){ return "我是:"+name1+",和"+name2+",跑步去了"; }
-
当带入的数据内容是"hello"时,则形参列表写 String s 即可
-
当带入的数据内容是66和"hello"时,则形参列表写 int i, String s 即可
-
若该方法不需要带入任何数据内容时,则形参列表位置啥也不写即可。
方法体的详解
- 成员方法体主要用于编写描述该方法功能的语句块
- 成员方法可以实现代码的重用,简化代码
方法的调用
- 引用变量名.成员方法名(实参列表);
p.show();
- 实际参数列表主要用于对形式参数列表进行初始化操作,因此参数的个数、类型以及顺序都要完全一致
- 实际参数可以传递直接量、变量、表达式、方法的调用等。
public class classTest { public static void main(String[] args) { Person p = new Person(); String aa = p.say(); System.out.println(aa); String run = p.run("李四"); System.out.println(run); p.walk(); } } class Person{ // 属性或成员变量 String name; int age; String address; //无参构造器 public Person(){} //有参构造器 public Person(String n,int a,String addr){ name=n; age=a; address=addr; } // 方法或函数 public void walk(){ System.out.println("每个人都会走路"); } public String run(String name){ return "我是:"+name+",跑步去了"; } public String say(){ return "人的名字是:" +name+ ",年龄是:"+age+",地址是:"+address; } // 代码块 { name="张三"; age=17; address="河南"; } //内部类 class moreInf{ String school; float weight; } }
Java_可变长形参
基本概念
- 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);
可变长参数
- 返回值类型 方法名(参数的类型… 参数名)
- 方法参数部分指定类型的参数个数是可以改变的,也就是0~n个 。
- 一个方法的形参列表中最多只能声明一个可变长形参,并且需要放到参数列表的末尾
package com.company;
public class Change_test {
public void test(String[] msg){
System.out.println("含字符串数组参数的test方法 ");
}
public void test1(String book){
System.out.println("****与可变形参方法构成重载的test1方法****");
}
public void test1(String ... books){
System.out.println("****形参长度可变的test1方法****");
}
public static void main(String[] args){
Change_test te = new Change_test();
//下面两次调用将执行第二个test方法
te.test1();
te.test1("aa" , "bb");
//下面将执行第一个test方法
te.test(new String[]{"aa"});
}
}
方法的传参过程
-
为main方法中的变量a、b、res分配空间并初始化
-
调用max方法,为max方法的形参变量ia、ib分配空间。
-
将实参变量的数值赋值到形参变量的内存空间中。
-
max方法运行完毕后返回,形参变量空间释放。
-
main方法中的res变量得到max方法的返回值。
-
main方法结束后释放相关变量的内存空间。
public class classTest { public static void main(String[] args) { int a = 5; int b = 6; IsMax m = new IsMax(); int res = m.max(a, b); System.out.println(res); } } class IsMax { int temp; int max(int ia, int ib) { if (ia > ib) { temp = ia; } if (ia < ib) { temp = ib; } if (ia == ib) { temp = 0; } return temp; } }
传参的相关概念
- 参数分为形参和实参,定义方法时的参数叫形参,调用方法时传递的参数叫实参。
- 调用方法时采用值传递把实参传递给形参,方法内部其实是在使用形参。
- 所谓值传递就是当参数是基本类型时,传递参数的值,比如传递i=10,真实传参时,把10赋值给了形参。当参数是对象时,传递的是对象的值,也就是把对象的地址赋值给形参
- 基本数据类型的变量作为方法的参数传递时,形参变量数值的改变通常不会影响到实参变量的数值,因为两个变量有各自独立的内存空间;
- 引用数据类型的变量作为方法的参数传递时,形参变量指向内容的改变会影响到实参变量指向内容的数值,因为两个变量指向同一块内存空间
- 当引用数据类型的变量作为方法的参数传递时,若形参变量改变指向后再改变指定的内容,则通常不会影响到实参变量指向内容的改变,因为两个变量指向不同的内存空间
package com.company;
public class Join_parma_01 {
// 基本数据类型的参数传递
public static void main(String[] args) {
int x = 5;
System.out.println("修改之前x = " + x);// 5
// x是实参
change(x);
System.out.println("修改之后x = " + x);// 5
}
public static void change(int x) {
System.out.println("change:修改之前x = " + x);// 5
x = 3;
System.out.println("change:修改之后x = " + x); // 3
}
}
运行结果如下:
引用数据类型传递样例
package com.company;
public class Join_parma_02 {
public static class Person{
int age;
}
public static void main(String[] args) {
Person obj = new Person();
obj.age = 5;
System.out.println("修改之前age = " + obj.age);// 5
// x是实参
change(obj);
System.out.println("修改之后age = " + obj.age);// 3
}
public static void change(Person obj) {
System.out.println("change:修改之前age = " + obj.age); // 5
obj.age = 3;
System.out.println("change:修改之后age = " + obj.age); // 3
}
}
运行结果如下:
对象作为参数传递给方法
package com.company;
public class join_parma_03 {
public static void main(String[] args){
Num n1 = new Num();
Num n2 = n1; // n1和n2引用同一对象,即它们有相同的引用值
n1.i = 0;
int x = 10;
System.out.println("调用方法method1前:n1.i = "+n1.i+"\tn2.i = "+n2.i+"\tx = "+x);
method1(n1,x);
System.out.println("调用方法method1后:n1.i = "+n1.i+"\tx = "+x);
System.out.println((n1 == n2) ? "n1和n2引用同一对象" : "n1和n2引用不同对象");
method2(n2);
System.out.println("调用method2后:n1.i = "+n1.i+" n2.i = "+n2.i);
System.out.println((n1 == n2) ? "n1和n2引用同一对象" : "n1和n2引用不同对象");
}
static void method1(Num num,int y){
num.i += y;
y --;
System.out.println("在退出method方法时:num.i = "+num.i+"\ty = "+y);
}
static void method2(Num num){
num = new Num();
num.i += 100;
System.out.println("退出method方法时: num.i = "+num.i);
}
public static class Num{
int i;
}
}
运行结果
- 首先创建
class Num 的对象 n1,并创建 Num n2 = n1
,所以n1和n2有着相同的引用值,n1,n2
都引用同一对象 - 对于method1方法来说,将n1的·值传递给了形参num,与n2和n1一样
- 在method1方法中对象num成员内容的任何改动,都会引起n1的内容改动。同时n1的变动也会引起n2的变动。
- 但是x传给y是值传递,所以y的变化则不会引起x的变化
- 对于method2来说,在它的函数体内重新申请了num的引用值,所以说对象num’的内容变动就不会再引起n2中内容的变化。
匿名对象
- 对不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。 例如:
new Person().shout();
- 如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。
- 经常将匿名对象作为实参传递给一个方法调用。
Java_成员变量与局部变量
- 在编程语言中,数据是存储在内存中的,变量就是对内存中数据的引用
- 变量的分类:成员变量与局部变量
- 在方法体外,类体内声明的变量称为成员变量。
- 在方法体内部声明的变量称为局部变量。
成员变量赋值的执行顺序
- 显式初始化、多个初始化块依次被执行(同级别下按先后顺序执行)
- 构造器再对成员进行初始化操作
- 通过
”对象.属性”
或”对象.方法
”的方式,可多次给属性赋值
成员变量和局部变量区别
- 成员变量是直接声明在类中的,修饰符有
private、public、static,final等
,有默认初始化值,在内存中的堆空间
中 - 局部变量是声明在方法形参或内部、代码块内、构造器内等,不能用权限修饰符修饰,可以用
final修饰
,没有默认初始化值,必须显式赋值后才能使用,数据存储在内存中调度栈空间中
变量作用域
- 局部变量必须声明才能使用,作用范围从声明开始,直到包含它的代码块结束
- 方法的参数范围涵盖整个方法。参数实际上是一个局部变量。
- for循环的初始化部分声明的变量,其作用范围在整个循环。
Java_堆和栈
堆(Heap)
- 堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
- Java虚拟机规范中的描述是:所有对象实例以及数组都要在堆上分配。
栈(Stack)
- 栈(Stack),是指虚拟机栈。虚拟机栈用于存储局部变量等。
- 栈用于存放程序运行过程当中所有的局部变量。一个运行的Java程序从开始到结束会有多次方法的调用。
- JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。
- 当某一个方法调用完成后,其对应的栈帧将被清除。
- 局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char 、 short 、 int 、 float 、 long 、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。
- 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
Java_package和 import
package和 import
都是Java关键字- package语句的由来: package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。
package
的语法格式:package 顶层包名.子包名 ;
package
对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次;package
通常用小写单词标识。通常使用所在公司域名的倒置com.atguigu.xxx
package的作用
- 定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识,则不可避免的出现命名冲突的问题。
- 在Java语言中,用包(package)的概念来解决命名冲突的问题
package
帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式package
可以包含类和子包,划分项目层次,便于管理package
控制访问权限
Java_JDK中主要的package介绍
java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
java.net----包含执行与网络相关的操作的类和接口。
java.io ----包含能提供多种输入/输出功能的类。
java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
java.text----包含了一些java格式化相关的类
java.sql----包含了java进行JDBC数据库编程的相关类/接口
java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)
Java_import关键字
- 为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的
类或全部类(.*)
。 import语句告诉编译器到哪里去寻找类
。import语法格式
:import 包名. 类名;
//import pack1.*;表示引入pack1.pack2包中的所有结构
import pack1.Test;
public class PackTest{
public static void main(String args[]){
Test t = new Test(); //Test类在pack1.pack2包中定义
t.display();
}
}
import关键字
- 在源文件中使用import显式的导入指定包下的类或接口
- 声明在包的声明和类的声明之间。
- 如果需要导入多个类或接口,那么就并列显式多个import语句即可
- 可以使用
java.util.*
的方式,一次性导入util
包下所有的类或接口。 - 如果导入的类或接口是
java.lang
包下的,或者是当前包下的可以省略import语句
。 - 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
- 如果已经导入
java.a
包下的类。那么如果需要使用a包
的子包下的类的话,仍然需要导入。 import static
组合的使用:调用指定类或接口下的静态的属性或方法
Java_finalize()方法
- Java允许在对象被垃圾收集器析构(回收)之前调用的方法,这个方法有固定的名字
finalize
,用来清除回收对象
package com.company;
public class Java_02 {
public static void main(String[] args) {
Cake c1 = new Cake(1);
Cake c2 = new Cake(2);
Cake c3 = new Cake(3);
c2 = c3 = null;
System.gc(); //调用Java垃圾收集器
}
}
class Cake extends Object {
private int id;
public Cake(int id) {
this.id = id;
System.out.println("Cake 启动 " + id );
}
protected void finalize() throws java.lang.Throwable {
super.finalize();
System.out.println("finlize启动 " + id );
}
}
- 关键字
protected
是一个限定符,它确保finalize()
方法不会被该类以外的代码调用。 - Java的内存回收可以有JVN自动完成,除此之外,还可以使用finalize()手动完成