Java基础语法(上)
Java简介
Java是一门程序开发语言. 1991年由sun公司的James Gosling和他的团队一起开发了一个叫Oak的语言. 在1995年更名为Java. 一直沿用至今.
Java是目前全世界使用人数最多的编程语言. Toibe 排行榜第一. https://www.tiobe.com/tiobe-index/
丰富的开源社区和非常多的开源框架.
国内各大一线公司都在使用Java.
特点:
- 简单: 针对C++简化了很多
Java相关概念:
JVM(Java Virtual Machine): java虚拟机, 用来模拟统一的硬件平台环境, 供java程序运行的 一个软件
JRE(Java Runtime Environment): java运行时环境. 里面包含了JVM和一些java运行时的类库
JDK(Java Development Kit): java开发包. 包含JRE和java开发工具包.
第一个Java程序
首先, 我们在c盘下创建一个文件夹. 叫test. 然后在test文件夹中.创建一个文本文档. 起名为first.java
写入以下代码
public class first{ public static void main(String[] args){ System.out.println("你好 终于写了一个程序了."); } }
使用命令javac对我们的程序进行编译
使用命令javac对我们的程序进行编译
注意: javac命令后面跟的是文件名
java命令后面跟的是类名. 也就是我们代码中public class 后面的那个名字
接下来. 我们对程序进行详解:
public class first{ ------> 这一行表示创建一个类. 类是java程序运行的最小单元. 必须要有类 public static void main(String[] args){ -----> java程序的入口. 一切从这里开始执行 System.out.println("你好 终于写了一个程序了."); ---> 让程序打印一句话, 内容是引号中的内容 } ---> 对应程序入口的结束 } --> 对应类的结束
Java中的注释
一. 单行注释
// 单行注释. 这一行内容会被jvm运行的时候过滤掉.
二. 多行注释
/* 多行注释 一次注释多行代码 */
三. 文档注释
/** * 文档注释 * 后期可以使用javadoc命令生成api文档 */
常用的是单行注释 // 和 文档注释 /*** /
一般在如下情况可以添加代码注释:
- 核心的解决方案
- 比较难懂的业务逻辑
- 记录代码的存在经历
变量
java中的变量:
数据类型 变量名 = 值;
本节, 我们只介绍一些最最常用的基本数据类型. 后面的进阶我们会进一步详细的介绍数据类型.
int
int主要表示的就是我们生活中使用的整数. 比如, 1, 10086等等.
int类型可以执行的操作: 加减乘除等. + - /
int a = 20; int b = 10; int c = a + b; System.out.println(“a + b = “ + c); int d = a - b; System.out.println(“a - b = “ + d); int e = a b; System.out.println(“a b = “ + e); int f = a / b; System.out.println(“a / b = “ + f);
double
double表示的是小数. 比如你去菜市场买个黄瓜花费了1.25元. 这就是小数. double类型的数据可以执行的操作和int基本相同. 不同的是. 计算结果一定是小数
double a = 1.88; double b = 1.75; double c = a + b; System.out.println(“a + b = “ + c); double d = a - b; System.out.println(“a - b = “ + d); double e = a b; System.out.println(“a * b = “ + e); double f = a / b; System.out.println(“a / b = “ + f);
String 字符串
String表示的是字符串. 主要是针对文字进行描述的. 这里要注意的是字符串(String) 的S必须大写
String s = “近日, 三胖又要制造超大号窜天猴了”; // 双引号括起来的内容就是字符串 System.out.println(“s = “ + s);
字符串可以进行加法运算. 表示字符串的拼接.
String s1 = “AAA”; String s2 = “BBB”; String s3 = s1 + s2; System.out.println(s3); String s4 = s3 + “, oh, yeah!”; System.out.println(s4);
boolean 布尔
boolean主要表示的是真或者假. 翻译过来就是 对和错. 真命题, 假命题
boolean a = true; boolean b = false; System.out.println(a); System.out.println(b);
boolean c = 1 > 2; boolean d = 2 > 1; System.out.println(c); System.out.println(d); int e = 10; // = 表示赋值 System.out.println(e == 10); // 判断是否相等要用 == System.out.println(e != 10);
```java // boolean值是用来判断条件的
变量的简单应用
int meals = 100+200+120+40; // 餐费 int traffic = 10 * 22; // 交通费 int clothing = 200+400+150; // 服装费 int all = meals + traffic + clothing; //总和 System.out.println("一共花费:" + all); // 一共花费:1430
用户输入
在java中使用输入功能需要使用Scanner类来完成.
import java.util.Scanner; // 使用Scanner必须要导入这个包. 关于导包后面会详解. 暂时先这么写 public class TestIf { public static void main(String[] args) { // 准备一个Scanner对象 Scanner sc = new Scanner(System.in); } }
具体操作
// 获取到用户输入的内容 Scanner sc = new Scanner(System.in); // 你想要什么样的数据? // 常用的有 // 获取到int类型的数据 int i = sc.nextInt(); System.out.println("i = " + i); // 获取到double类型的数据 double d = sc.nextDouble(); System.out.println("d = " + d); // 获取到字符串. 以回车为结尾 String line = sc.nextLine(); System.out.println("line = " + line);
应用: 计算这个月的零花钱
Scanner sc = new Scanner(System.in); // 提示 System.out.println("请输入您的工资:"); // 接收工资 double salary = sc.nextDouble(); // 显示工资 System.out.println("工资是:" + salary); // 计算零花钱 double pin = salary * (1-0.95); // 显示零花钱 System.out.println("零花钱:" + pin);
If语句
Scanner sc = new Scanner(System.in); System.out.println("请输入你一个月多少零花钱:"); double pin = sc.nextDouble(); if(pin > 500){ System.out.println("洗脚城走一波"); } else { System.out.println("捡一块砖头自己回家蹭"); } System.out.println("happy");
// 输入考试分数 Scanner sc = new Scanner(System.in); int score = sc.nextInt(); if(score >= 100){ System.out.println("优秀"); } else if (score >= 80 ){ System.out.println("良好"); } else if (score >= 70 ){ System.out.println("中等"); } else if (score >= 60 ){ System.out.println("及格"); } else { System.out.println("不及格"); }
While语句
System.out.println("1. 登录"); System.out.println("2. 找个怪多的地方"); int i = 0; while(i < 5){ System.out.println("3. F1~ 来自东方的神秘力量."); System.out.println("4. 换个地方继续."); i = i + 1; } System.out.println("5. 没意思, 走了~");
方法
- 写一个试试一个能从1数到100的方法, 并调用
public class TestMethod { public static void count100(){ for(int i = 1; i <= 100; i++){ System.out.println(i); } } public static void main(String[] args) { count100(); } }
- 方法的重载 (方法的名字相同, 参数的个数或类型不同)
public class TestMethod { public static int add(int a, int b){ System.out.println("两个int"); return a + b; } public static long add(int a, long b){ System.out.println("一个int, 一个long"); return a + b; } public static double add(int a, double b){ System.out.println("一个int, 一个double"); return a + b; } public static void main(String[] args) { System.out.println(add(10, 20)); System.out.println(add(10, 20L)); System.out.println(add(10, 1.25)); } }
面向对象
- 用面向对象的思维来完成植物大战僵尸
public class Plant { String name; int attack; int hp; public Plant(String name, int attack, int hp){ this.name = name; this.attack = attack; this.hp = hp; } public void fight(Zombie zombie){ System.out.println(this.name + "正在攻击:" + zombie.name); zombie.hp -= this.attack; System.out.println(zombie.name+"还剩下"+zombie.hp+"血量"); } }
public class Zombie { String name; int attack; int hp; public Zombie(String name, int attack, int hp){ this.name = name; this.attack = attack; this.hp = hp; } public void fight(Plant plant){ System.out.println(this.name + "正在攻击:" + plant.name); plant.hp -= this.attack; System.out.println(plant.name+"还剩下"+plant.hp+"血量"); } }
public class Client { public static void main(String[] args) { Plant p1 = new Plant("豌豆荚", 10, 100); Zombie zb = new Zombie("铁通僵尸", 20, 300); p1.fight(zb); p1.fight(zb); p1.fight(zb); p1.fight(zb); p1.fight(zb); zb.fight(p1); } }
静态变量 (被static修饰的变量会被所有的对象共享, 并且, 在内存里只会保留一份)
public class Person{ String name; String address; static String country = "大清"; public Person(String name, String address){ this.name = name; this.address = address; } public static void main(String[] args){ Person p1 = new Person("李大猛", "北京八大胡同"); Person p2 = new Person("花花", "北京朝阳"); p1.country = "民国"; System.out.println(p1.country); System.out.println(p2.country); // 民国 } }
静态方法
public class Person{ public static void huo(){ System.out.println("是人都想火"); } public static void main(String[] args){ huo(); // 由于是自己类. 可以直接访问静态方法 Person.huo();// 最好呢, 还是用类名去访问. } }
在创建对象的时候, 首先加载的是静态的内容, 然后才是非静态内容.
在静态方法里, 不能使用this.
也不能直接调用自己类中的其他成员(方法, 变量). 但是反过来是可以的.
重点: 静态的东西不属于对象, 直接属于类, 优先于对象产生. 使用的时候使用类名去访问.
访问权限
释义 | 自己类 | 自己包 | 其他包 | |
---|---|---|---|---|
public | 公共的 | OK | OK | OK |
default | 默认的 | OK | OK | NO |
private | 私有的 | OK | NO | NO |
package com.dylan.bao; public class Person { String def = "def"; // 默认啥都不写就是包访问权限 public String pub = "pub"; // 公共的 private String pri = "pri"; // 自己的 public static void main(String[] args) { Person p = new Person(); // 自己类里,都没问题 System.out.println(p.def); System.out.println(p.pub); System.out.println(p.pri); } }
自己包里的其他类试试
package com.dylan.bao; public class TestPackagePerson { public static void main(String[] args) { Person p = new Person(); // 自己包里. private不行了 System.out.println(p.def); System.out.println(p.pub); // System.out.println(p.pri); // 报错了 } }
一般情况, 我们很少用包访问权限. 这种权限并不舒服. 说白了. 你家里的东西要么是都能让人看的, 要么就是自己用的. 很少会专门准备一些东西给你的邻居用的. 程序也一样. 很少会用默认的访问权限.
getter and setter
package com.xyq.bao; public class Person { private String name; private int age; // 设置名字 public void setName(String name){ this.name = name; } // 获取名字 public String getName() { return name; } // 获取年龄 public int getAge() { return age; } // 设置年龄 public void setAge(int age){ if(age < 0){ this.age = 0; } else { this.age = age; } } public void chi(){ System.out.println(this.name+"在吃东西"); } }
IDEA软件中, 快捷键: 空白处, 右键-> generate -> getter and setter -> ctrl + A -> OK ! enjoy
~
继承
写个妖怪
package com.dylan.bao; public class YaoGuai { private void paSi(){ System.out.println("妖怪都怕死"); } public void chiRen(){ System.out.println("妖怪喜欢吃人"); } }
写个黑熊
package com.dylan.bao; public class HeiXiong extends YaoGuai { }
测试一下
package com.dylan.bao; public class TestExtends { public static void main(String[] args) { HeiXiong hx = new HeiXiong(); hx.chiRen(); // hx.paSi(); //报错, 找不到怕死 } }
所以从另一个角度讲, 子类其实是对父类进行了扩展. 在父类已经给了一些方法和属性的基础上再加一点儿新功能. 可以节省很多的代码.
注意: java只能单继承. 说白了. 每个儿子只能有一个爹
多态
package com.dylan.bao; public class Animal{ public void eat(){ System.out.println("动物吃东西"); } }
package com.dylan.bao; public class Dog extends Animal{ public void eat(){ System.out.println("狗吃骨头"); } }
package com.dylan.bao; public class Cat extends Animal{ public void eat(){ System.out.println("猫吃鱼"); } }
把子类的对象赋值给父类的变量. 这个在java里被称为向上转型.
向上转型的优点: 自动转型. 把不相关的东西转化成相同的数据类型. 猫, 狗, 鹦鹉都当成动物来看~~
package com.dylan.bao; public class Person{ public void feed(Animal ani){ ani.eat(); } }
package com.dylan.bao; public class Test { public static void main(String[] args) { Person p = new Person(); Animal c = new Cat(); Animal d = new Dog(); p.feed(c); f.feed(d); } }
多态的三个要素:
要有继承关系
要重写
要向上转型
优点: 让程序有超强的可扩展性.
如果你想把父类的变量转化回子类的类型. 就必须要强转
(转化之后的类型) 变量
public static void main(String[] args){ Animal ani = new Cat(); //向上转型 Cat c = (Cat) ani;//必须要强转 }
final关键字
被final修饰的变量: 不可以被重新赋值, 又被称为常量.
被final修饰的方法: 不可以被重写
被final修饰的类: 不可以被继承
package com.dylan.bao; public final class Diamonds { private final int weight = 100; public void change(){ this.weight = 200; // 报错. 被final修饰. 不可以被修改 } public final void bling(){ System.out.println("钻石是不灵不灵的"); } }
package com.dylan.bao; public class PinkDiamonds extends Diamonds { public void bling(){ // 被final修饰的方法不可以被重写 System.out.println("钻石是不灵不灵的"); } }
抽象类
package com.dylan.bao; public abstract class Animal { // 含有抽象方法的类必须是抽象类 public abstract void chi(); // 抽象方法 public void dong(){ // 抽象类也可以有正常的方法 System.out.println("估拥"); } }
package com.dylan.bao; public class Cat extends Animal{ // 继承抽象类, 必须重写抽象方法 public void chi(){ // 猫是有确定的吃的方式的. System.out.println("猫吃鱼"); } }
这样间接的. 我们使用抽象类就对子类进行了约束. 要求子类必须有一个xxx方法.
接口
接口其实就是一种特殊的抽象类. 接口里所有的方法都是抽象方法.
package com.dylan.bao; /** * 注意: 这里不能写class. 要写interface */ public interface Valuable { void sell(); // 由于接口里所有的方法都是public abstract 所以不放修饰符. 默认是全局抽象 }
接口既然全都是抽象方法, 那如何使用呢? 和抽象类一样. 也要借助于子类. 但是, 接口终归是接口, 这玩意不是类. 所以, 记住
继承接口的只能是接口.
那接口和类之间怎么产生关系呢?
类可以实现接口(implements), 实现和继承其实从语义上讲是一样的.
比如, 熊猫是一种值钱的东西
package com.dylan.bao; // 类实现接口. 类继承类. 接口继承接口. public class Panda implements Valuable { @Override // 重写 public void sell() { System.out.println("熊猫可以卖个好价钱"); } }
类与类之间: 继承关系
接口和接口: 继承关系
类和接口: 实现关系
在这里. 我们把panda称之为Valuable的一个实现类, 接口和接口实现类之间其实就是一种另类的继承关系. 接口的实现类必须实现(重写)接口中所有的抽象方法. 否则这个类必须是一个抽象类. 接口也可以对类进行约束.
用抽象类不也挺好的么. 为什么非要搞出一个接口?
java中一个类只能有一个父类. 这就导致一个问题. 说, 熊猫是一种值钱的东西. 熊猫继承值钱的东西. 但是, 熊猫还是一个受保护的东西啊. 熊猫再继承受保护的东西. 那就不对了. java是单继承啊. 语法上不让你这么写. 怎么办? 接口可以多实现
~
package com.dylan.bao; public class Panda extends Animal implements Valuable, Protectable { @Override public void sell() { System.out.println("熊猫可以卖个好价钱"); } @Override public void protect() { System.out.println("熊猫应该被保护起来"); } @Override public void chi() { System.out.println("熊猫吃竹子"); } }
package com.xyq.bao; public class Test { public static void main(String[] args) { Animal ani = new Panda(); ani.chi(); Valuable val = new Panda(); val.sell(); Protectable pro = new Panda(); pro.protect(); Panda pan = new Panda(); pan.chi(); pan.protect(); pan.sell(); } }
一个类可以实现多个无关的接口
一个接口可以被多个无关的类实现
接口最重要的作用: 把不想关的两个物体连接起来. 通过接口连接.
接口里都是方法么? 不, 接口里也有变量, 但是接口里的变量全部都是全局静态常量.
public interface Valuable{ double money = 100; // 相当于 public static final double money = 100; } public class Client{ public static void main(String[] args){ System.out.println(Valuable.money); //可以使用类名直接调用. 静态的 Valuable.money = 200; // 报错. 不可以被修改 } }
注意: 我们很少会在接口里设置变量. 更多的是使用接口来统一数据类型. 和对实现类进行约束.
equals 和 ==
package com.dylan.bao; public class Cat { private String name; private String color; public Cat(String name, String color) { this.name = name; this.color = color; } public static void main(String[] args) { Cat c1 = new Cat("小花", "红色"); Cat c2 = new Cat("小花", "红色"); System.out.println(c1 == c2); //false System.out.println(c1.equals(c2)); //false } }
== 判断的是两只猫是不是同一只猫. 判断内存地址
equals我们调用的是object里的equals, 和==没有区别
package com.dylan.bao; public class Cat { private String name; private String color; public Cat(String name, String color) { this.name = name; this.color = color; } // 手动给出equals方法 public boolean equals(Cat c){ if(this.name == c.name && this.color == c.color){ return true; } else { return false; } } public static void main(String[] args) { Cat c1 = new Cat("小花", "红色"); Cat c2 = new Cat("小花", "红色"); System.out.println(c1 == c2); //false System.out.println(c1.equals(c2)); //true } }
搞定. 我们通过==来判断两只猫是否是同一只猫. 通过equals来判断两只猫长的是不是一样.
接下来, 看一个玄学问题
package com.dylan.bao; public class Test { public static void main(String[] args) { String a1 = "竹鼠"; String a2 = "竹鼠"; System.out.println(a1 == a2); // true System.out.println(a1.equals(a2)); // true String a3 = new String("节奏狗"); String a4 = new String("节奏狗"); System.out.println(a3 == a4); // false System.out.println(a3.equals(a4)); // true } }
为什么会这样. 因为字符串是我们使用频率最高的一种数据类型. java会自动帮我们对字符串进行缓存. 发现一样的字符串了就不再创建新的了. 所以a1和a2内存地址是一样的. 所以两个都是真. a3在创建的时候new了一次. a4也new了一次. 此时, “节奏狗” 三个字被缓存. 但是. new的时候是要创建对象的. 对象再引入”节奏狗”三个字. 所以. 两个对象的地址是不一样的. 但是内容是一样的.
综上, 我们在判断两个字符串是否一致的时候, 一定要用equals 这样就是很稳定的判断内容是否一样.
toString()
package com.dylan.bao; public class Cat { private String name; private String color; public Cat(String name, String color) { this.name = name; this.color = color; } public String toString(){ return "一只"+this.color+"猫, 名字是:"+this.name; } public static void main(String[] args) { Cat c = new Cat("韩梅梅", "绿色"); System.out.println(c); // 一只绿***, 名字是:韩梅梅 } }
instanceof
package com.xyq.bao; public class Test { public static void main(String[] args) { Animal a = new Cat(); if(a instanceof Cat){ System.out.println("这个动物是一只猫"); } else { System.out.println("这个动物不是一只猫"); } } }
内存分析
package com.xyq.bao; public class Person { private String name; private int age; private String address; public static int num = 0; public Person(String name, int age, String address){ this.name = name; this.age = age; this.address = address; num++; } public static void main(String[] args) { Person p1 = new Person("少林寺", 18, "河南嵩山"); Person p2 = new Person("吐鲁番", 12, "新疆"); Person p3 = new Person("海南岛", 16, "海南"); Person p4 = new Person("北戴河", 4, "河北"); System.out.println(Person.num); } }
在java中一共会分为4块内存区域. 分别是: 堆, 栈, 代码区, 数据区.
堆: 放对象. new的东西都在这里
栈: 局部变量. 基础数据类型变量.
代码区: 类.
数据区: 常量池, 静态变量.
常量池: 我们前面讲equals的时候. 说过java会帮我们缓存一些数据. 这些数据就放在常量池里
接下来.我们先分析第一句话
Person p1 = new Person(“少林寺”, 18, “河南嵩山”);
其余的同理
参数传递
基本数据类型是值传递
package com.xyq.bao; public class TestMethod { public static void change(String b){ b = "aaa"; int hashCode = System.identityHashCode(b); System.out.println(hashCode); //257895351 } public static void main(String[] args) { String a = "bbb"; change(a); System.out.println(a); // 10 int hashCode = System.identityHashCode(a); // 查看到虚拟机映射的地址 HASHCODE System.out.println(hashCode); // 1929600551 } }
对象是引用传递
public class Temp { public static void change(Person p){ p.setName("ABC"); System.out.println(p); // Person@f5f2bb7 int hashCode = System.identityHashCode(p); // 查看到虚拟机映射的地址 HASHCODE System.out.println(hashCode); // 257895351 } public static void main(String[] args) { Person p = new Person("小明", "male"); change(p); System.out.println(p.name); // ABC int hashCode = System.identityHashCode(p); // 查看到虚拟机映射的地址 HASHCODE System.out.println(p); // Person@f5f2bb7 System.out.println(hashCode); // 257895351 } }
异常处理
异常类的根: Throwable
两个分支: Error和Exception
Exception又分为RuntimeException和其他Exception
RuntimeException表示运行时异常. 只有跑起来才知道错了.
其他Exception: 不用跑就知道错了
Error: 系统级错误. 程序员一般不好处理.
try ... catch
在idea里可以ctrl+alt+t快速的给代码加上try…catch
package com.dylan.bao; public class CreateException { public static void main(String[] args) { try { System.out.println(1/0); } catch (ArithmeticException e) { System.out.println("出现错误, 请联系系统管理员"); } } }
throws和throw
public class Test { public static void chu(int a, int b) throws Exception{ //告诉外面, 我要扔出来一个错误 if (b==0){ // 0不能做除数 // 主动抛异常 throw new Exception("你不可以给我一个0"); // 真正的向外抛出一个异常 } else { System.out.println(a/b); } } public static void main(String[] args) { try { chu(1, 2); } catch (Exception e) { e.printStackTrace(); // System.out.println(e.getMassage()); } } }
如果方法中主动向外抛异常, 那么这个方法必须要通知外界去处理异常, 也就是说, 方法内部有throw, 方法的声明就一定有throws. 反之则不一定.
自定义异常
模拟男女澡堂子, 女方不能进男澡堂
public class Person { String name; String gender; public Person(String name, String gender) { this.name = name; this.gender = gender; } }
public class Zaotangzi { public void male(Person p) throws GenderException { if(p.gender.equals("男")){ System.out.println("Welcome!"); } else{ throw new GenderException("性别不对, 这里是男澡堂子!"); } } }
public class GenderException extends Exception{ public GenderException(String msg){ super(msg); } }
public class Test { public static void main(String[] args) throws GenderException { Person p = new Person("小明", "女"); Zaotangzi z = new Zaotangzi(); z.male(p); } }