java学习03day
Java的一些特性
变量
java的变量相对于c语言而言不能重复定义会爆错
int e,f = 30;
上述的代码相当于f为30,e没有进行复制
强类型语言:每个变量都必须声明其类型
数据类型
数据类型分为:1、基本数据类型:数值型(整数类型(byte、short、int、long)浮点类型(float、double))、字符型(char)、布尔型(boolean)
2、引用数据类型:类(class)、接口(interface)、数组。
在 Java 中,输出可以以多种形式进行,但最终都是通过字符流或字节流的方式输出到控制台、文件或其他输出设备。以下是一些常见的输出方式及其特点:
在输出的时候+先执行加法操作则之后如果是数与数的操作则还是加法操作
如果先是连接操作则下面还是连接操作:
System.out.println("输出的是"+now);
System.out.println("结果为"+5+6);
在输出超过int类型的整数的时候则要在数值的最后添加L
long a = 1234567899L;
字符串使用float的时候则要在字符串的最后添加f:
float now = 3.14f;
方法(函数)
与c++的区别:
-
C++ 函数:
- 函数是独立的代码块,可以在全局范围内定义,也可以定义在类内部(称为成员函数)。
- C++ 支持全局函数和命名空间中的函数。
-
Java 方法:
-
方法是类的一部分,必须在类内部定义。Java 不支持全局函数。
-
方法是对象的行为,通常与对象的状态(属性)相关联。
-
C++ 支持函数重载(同名函数参数不同)和虚函数(支持多态,通过基类指针或引用调用派生类的方法)。
-
C++ 中的虚函数通过
virtual
关键字声明,允许在派生类中重写。 -
Java 也支持方法重载和方法重写。重写的方法必须与父类中的方法具有相同的名称和参数列表。
-
在 Java 中,所有的方法默认都是虚拟的,除非使用
final
或static
关键字修饰。
-
在 Java 中,函数参数不能有默认值,因此你提供的这个代码片段是无效的。Java 不支持像 C++ 那样在方法参数中指定默认值。
java方法的重载:在同一类中的方法名相同,形参列表不同的多个方法构成方法的重载,其中的形参列表可以是类型不同、顺序不同、个数不同
数组
在 Java 中,数组的定义和初始化是两个不同的概念,它们的顺序和方式与 Java 的内存管理和虚拟机(JVM)的工作机制有关。下面是对这一现象的详细解释:
1. 数组的定义与初始化
-
定义:在 Java 中,定义数组是指声明一个数组变量,指定其类型和名称,但并不分配内存。
int[] myArray; // 定义一个整型数组变量
-
初始化:初始化数组是指分配内存并设置数组的初始值。可以通过以下方式进行初始化:
myArray = new int[10]; // 初始化数组,分配内存空间
或者结合定义和初始化:
int[] myArray = new int[10]; // 定义并初始化数组
2. 虚拟机与内存管理
- 内存分配:在 Java 中,数组的内存分配是由 JVM 管理的。当你使用
new
关键字初始化数组时,JVM 会在堆内存中分配相应的空间。JVM 负责管理内存的分配和释放,这与虚拟机的设计有关。 - 类型安全:Java 是一种强类型语言,因此在定义数组时需要指定数组的类型。这是为了确保在使用数组时能够进行类型检查,避免类型不匹配的错误。
3. 为什么需要先定义再初始化
- 清晰的语义:通过先定义数组,程序员可以清楚地知道该变量的类型和用途。这有助于代码的可读性和可维护性。
- 避免空指针异常:在 Java 中,未初始化的数组变量默认值为
null
。在使用数组之前必须先初始化它,这样可以减少空指针异常的风险。 - 内存管理:通过分开定义和初始化,可以更灵活地管理内存。例如,你可以在条件语句中根据需要来初始化数组。
4. 总结
数组在 Java 中需要先定义再初始化的原因与 Java 的内存管理、类型安全以及代码的可读性等因素有关。这并不是因为虚拟化的缘故,而是 Java 语言设计的基本原则和 JVM 的内存管理机制共同导致的。通过这种方式,Java 提供了更安全和更清晰的编程体验。
数组的增强输出:
int[] arr;
arr = new int[4];
int[] now = new int[66];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
System.out.println("数组的查看:增强for循环方式:");
for(int num:arr){//对arr数组进行遍历,遍历出来的每一个元素用num进行接收
System.out.println(num);
}
增强for循环和正常for循环的区别:
1. 用途
- 增强
for
循环:- 主要用于遍历集合或数组,简化了代码,避免了显式的索引操作。
- 适合于只需要读取元素的场景,不适合于需要修改元素的情况。
- 正常
for
循环:- 更灵活,可以自由控制循环的起始位置、终止条件和步进值。
- 适合于需要修改元素、访问特定索引或需要复杂逻辑的场景。
2. 可读性
- 增强
for
循环:- 更加简洁和易读,特别是在处理集合时,代码更清晰。
- 减少了错误的可能性,如索引越界等。
- 正常
for
循环:- 代码相对较长,可能会增加出错的机会,尤其是在复杂的循环条件下。
3. 性能
- 增强
for
循环:- 在大多数情况下,性能与正常
for
循环相似,因为它在内部仍然使用迭代器或索引。 - 但在某些情况下,增强
for
循环可能会略微影响性能,特别是在处理大型数据集时。
- 在大多数情况下,性能与正常
- 正常
for
循环:- 由于可以直接使用索引访问数组元素,可能在某些情况下表现得更高效,尤其是在数组操作中。
总结
-
增强
for
循环 更加简洁和易读,适合用于遍历集合或数组,但不适合需要修改元素或复杂逻辑的情况。 -
正常
for
循环 提供了更多的灵活性,适合需要对索引进行精细控制的场景。
类和对象
类:对对象向上抽取出像的部分、公共的部分一次形成类,类就相当于一个模板
对象:模板下具体的产物可以理解为具体的对象,对象就是一个一个及具体的实例,就相当于这个模板下具体的产品。
java中先定义类,在创建对象
类:
package com.day01.test3;
/*
* 人类
* */
public class Person {
// 特性-属性-名词
String name;
int age;
int height;
// 行为-方法-动词
// 定义一个学习的方法
public void study(){
System.out.println("学海无涯苦作舟");
}
}
对象:
package com.day01.test3;
public class Test {
// 程序的入口(不是大类的程序入口是小类之间的调用)
public static void main(String[] args) {
//对Person类的对象创建,创建了一个Person对象
Person p1 = new Person();
p1.name = "李薇";
p1.age = 24;
p1.height = 180;
System.out.println(p1.name);
System.out.println(p1.age);
// 调用方法
p1.study();
}
}
构造器
对于一个类而言,一般有三种常见的成员:属性方法、构造器、
这三种成员都可以定义零个或多个。
构造方法(构造器),是一个创建对象时被自动调用的特殊方法,用于对象的额初始化。java呕吐难过new关键字来调用构造器,从而返回该类的实例。
类:
package com.day01.test3;
/*
* 人类
* */
public class Person {
// 特性-属性-名词
String name;
int age;
int height;
// 行为-方法-动词
// 定义一个学习的方法
public void study(){
System.out.println("学海无涯苦作舟");
}
// 构造器的参数名字,如果和属性名字重名,就会发生就近原则
// 如果重名,你想要给属性赋值,那么就在想要表达属性的变量前加上this.来修价
public Person(){
System.out.println("45天秤神");
}
public Person(int age){
System.out.println("李薇的年龄为" + age);
this.age = age;
this.name = "王八蛋";
this.height = 156;
}
}
对象的生成:
package com.day01.test3;
public class Test2 {
public static void main(String[] args) {
/*
* 创建一个Persion类的对象
* 其中的Person是一个空的构造方法
* new关键字对方法进行调用 -》构造器的作用:底层就会自动帮我们创建对象之后,进行初始化的操作。
* 如果一个类没有显示编写构造器的话,那么系统会为这个类默认分配一个空的构造方法
* 调用构造器以后,对对象进行初始化作,将对象的地址返回给p
* 以后尽量保证空构造器的存在,以后学到框架,某些框架底层需要空构造器,如果你没有添加就会报错。
* 如果一个类中有构造器,那么系统就不会帮你分配默认的空构造器
* */
Person p = new Person(20);
}
}
重点特性:
-
其中的Person是一个空的构造方法
-
new关键字对方法进行调用 -》构造器的作用:底层就会自动帮我们创建对象之后,进行初始化的操作。
-
如果一个类没有显示编写构造器的话,那么系统会为这个类默认分配一个空的构造方法
-
调用构造器以后,对对象进行初始化作,将对象的地址返回给p
-
以后尽量保证空构造器的存在,以后学到框架,某些框架底层需要空构造器,如果你没有添加就会报错。
-
如果一个类中有构造器,那么系统就不会帮你分配默认的空构造器
构造方法也是方法,只不过有特殊的作用而已。与普通方法一样,构造方法也可以重载。(一般都会进行重载一个空的构造方法)
封装
我们程序设计追求“高内聚,低耦合
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系
统的可扩展性、可维护性,提高程序的安全性。通俗的说,把该隐藏的隐藏起
来,该暴露的暴露出来。这就是封装性的设计思想。
示例代码:
package com.day01.test4;
public class Girl {
private int age;
public void shezhiAge(int age){
if(age>18){
this.age = 18;
}else{
this.age = age;
}
}
public int Age(){
return this.age;
}
}
package com.day01.test4;
public class Tets {
public static void main(String[] args) {
Girl g = new Girl();
g.shezhiAge(33);
System.out.println(g.Age());
}
}
上述的代码就展示了内部高耦合,(通过函数范围对象内部的数据与直接访问内部的数据之间的区别),通过函数访问内部的数据,开发者可以根据自己的意愿对对象内部的数据进行限制。
alt+insert:能够快捷生成get和set方法。
继承
类是对对象的抽象
继承是对类的抽象
超类/基类/父类:从众多的类中在进行抽象出来的公共的类
继承的格式:子类 extends 父类
继承的好处:
1.提高了代码的复用性
2.便于代码的扩展
3.为了多态的使用,是多态使用的前提
示例代码:
package com.day01.test5;
public class Person {
//父类中的公共属性
private int age;
private String name;
private double height;
// 父类中公共的方法
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
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 eat(){
System.out.println("人类可以吃饭");
}
public void sleep(){
System.out.println("人类可以睡觉");
}
public void shout(){
System.out.println("人类可以喊叫");
}
}
package com.day01.test5;
public class Student extends Person{//子类student继承父类Persoin
//定义子类额外的、扩展的方法
private int sno;
// 定义子类的额外的、扩展的方法
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
// 学习
public void study(){
System.out.println("学生可以进行学习");
}
}
package com.day01.test5;
public class Test {
public static void main(String[] args) {
//定义一个子类具体的对象
Student s = new Student();
s.setAge(10);
s.setSno(102030);
s.setName("雷伟");
s.setHeight(181.11);
s.study();
s.eat();
s.shout();
System.out.println(s.getAge());
}
}
方法的重写
方法的重写:
发生在子类和父类中,当子类对父类提供的方法不满意的时候,
要对父类的方法进行重写
方法的重写有严格的格式要求:
子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。
重载和重写的区别:
重载:在同一个类中,当方法名相同,形参列表不同的时候,多个方法构成了重载
重写:在不同的类中,子类对父类提供的方法不满意,对父类的方法进行重写
多态
多态:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象
去完成时会产生出不同的状态。同一种行为,不同的子类呈现出来的状态是不
同的。
pwnda(自己的理解):多态是为了让一个函数能够传入不同的参数(逻辑上的不同的参数)(前提这些执行的方法有着相同的抽象的父类),从而可以在相同的一个方法根据传入参数的不同执行不同的效果。真正传入的参数就是两者共同的父类。(合成的写法就是用子类来初始化这个父类的对象),
前提在子类中对父类的方法进行了重写。并且在多态执行的函数中执行的就是重写的方法
示例代码:
抽象的父类:
package com.day01.test7;
public class Animal {
public void shout(){
System.out.println("叫!!!!!!");
}
}
子类:
package com.day01.test7;
public class Dog extends Animal{
// 喊叫
public void shout(){
System.out.println("狗-汪汪叫");
}
public void guard(){
System.out.println("汪汪队立大功");
}
}
子类:
package com.day01.test7;
public class Cat extends Animal{
public void shout(){
System.out.println("猫:喵喵喵叫");
}
public void scratch(){
System.out.println("猫抓人");
}
}
package com.day01.test7;
public class Test {
public static void main(String[] args) {
// 创建女孩的实例、对象:
Girl now = new Girl();
// 创建猫的实例
// Cat c = new Cat();
// Dog d = new Dog();
// now.play(c);
// now.play(d);
Animal an;//定义一个具体的动物
Cat c = new Cat();//具体的猫
an = c;//让动物是一只具体的猫
// 合成一句话:Animal an = new Cat();
now.play(an);
}
}
异常处理
try-catch-finally-throw-throws
异常就是在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。
所需文件找不到
网络连接不通或中断
算术运算错 (被零除...)
数组下标越界
装载一个不存在的类或者对null对象操作
类型转换异常
Java提供异常处理机制。它将异常处理代码和和业务代码分离,使程序更优雅,更好的
容错性,高键壮性。
Java的异常处理是通过5个关键字来实现的:try、catch、finally、throw、throws
程序出错捕获之后可以继续执行后面的代码
try-catch执行情况
情况1:try块中代码没有出现异常
不执行catch块代码,执行catch块后边的代码
情况2:try块中代码出现异常,catch中异常类型匹配(相同或者父类)
Java会生成相应的异常对象,Java系统寻找匹配的catch块,执行catch块代码,执行
catch块后边的代码。try块中尚未执行的语句不会执行。
情况3:try块中代码出现异常,catch中异常类型不匹配
不执行catch块代码,不执行catch块后边的代码,程序会中断运行
catch块中如何处理异常
其中一种方式:自定义内容输出
注:exception可以匹配所有的异常(是所有错误子类的父类)
示例:
package com.day01.test8;
public class Test1 {
public static void main(String[] args) {
try{
int num1 = 12;
int num2 = 0;
System.out.println("结果为:"+num1/num2);
}catch(Exception ex){
System.out.println("对不起,程序出现了错误" + ex);
}finally {
System.out.println("程序无论是否出现异常,这个逻辑都会执行的");
}
System.out.println("执行到这里了!!!!!!!");
System.out.println("执行到这里了!!!!!!!");
System.out.println("执行到这里了!!!!!!!");
}
}
finally:无论程序中是否出现异常程序都会执行finally中的代码块
throw:自己进行异常的抛出
throws:将该异常抛给调用该函数的函数
throw和throws的区别:
(1)位置不同:
throw:方法内部
throws:方法的签名处,方法的声明处
(2)内容不同:
throw+异常对象
throws+异常的类型
(3)作用不同:
throw:异常出现的源头,制造异常,
throws:在方法的声明处,告诉方法的调用者,这个方法中可能会出现我声明的这些异
常。然后调用者对这个异常进行处理:要么自己处理要么再继续向外抛出异常。
集合
数组的缺点-》 集合的优点
- 数组一旦指定了长度,那么长度就被确定了,不可以更改。
- 删除,增加元素 效率低。
- 数组中实际元素的数量是没有办法获取的,没有提供对应的方法或者属性来获取
- 数组存储:有序、可重复,对于无序的,不可重复的场合数组不能满足要求