Я знаю, що у Java немає вказівників, але я чув, що програми Java можна створювати за допомогою покажчиків і що це можуть зробити нечисленні, хто є фахівцями в галузі Java. Це правда?
Я знаю, що у Java немає вказівників, але я чув, що програми Java можна створювати за допомогою покажчиків і що це можуть зробити нечисленні, хто є фахівцями в галузі Java. Це правда?
Відповіді:
Усі об’єкти в Java є посиланнями, і ви можете використовувати їх як покажчики.
abstract class Animal
{...
}
class Lion extends Animal
{...
}
class Tiger extends Animal
{
public Tiger() {...}
public void growl(){...}
}
Tiger first = null;
Tiger second = new Tiger();
Tiger third;
Перенаправлення нуля:
first.growl(); // ERROR, first is null.
third.growl(); // ERROR, third has not been initialized.
Проблема згладжування:
third = new Tiger();
first = third;
Втрата клітин:
second = third; // Possible ERROR. The old value of second is lost.
Ви можете зробити це безпечним, спочатку переконавшись, що більше немає потреби в старому значенні секунди або призначив іншому вказівнику значення секунди.
first = second;
second = third; //OK
Зауважте, що надання другого значення іншими способами (NULL, new ...) - це стільки ж потенційна помилка і може призвести до втрати об'єкта, на який він вказує.
Система Java викине виняток ( OutOfMemoryError
), коли ви зателефонуєте за новим, і розподільник не може виділити запитувану комірку. Це дуже рідко і, як правило, є наслідком рекурсії, що біжить.
Зауважте, що з мовної точки зору, відмова від об'єктів до сміттєзбірника зовсім не є помилками. Це просто те, що потрібно усвідомлювати програмісту. Одна і та ж змінна може вказувати на різні об'єкти в різний час, і старі значення будуть повернені, коли жоден покажчик не посилається на них. Але якщо логіка програми вимагає збереження хоча б однієї посилання на об’єкт, це призведе до помилки.
Новачки часто роблять таку помилку.
Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed.
Що ви, мабуть, хотіли сказати:
Tiger tony = null;
tony = third; // OK.
Неправильний кастинг:
Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler.
Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.
Покажчики на С:
void main() {
int* x; // Allocate the pointers x and y
int* y; // (but not the pointees)
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
*y = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
*y = 13; // Dereference y to store 13 in its (shared) pointee
}
Покажчики на Java:
class IntObj {
public int value;
}
public class Binky() {
public static void main(String[] args) {
IntObj x; // Allocate the pointers x and y
IntObj y; // (but not the IntObj pointees)
x = new IntObj(); // Allocate an IntObj pointee
// and set x to point to it
x.value = 42; // Dereference x to store 42 in its pointee
y.value = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
y.value = 13; // Deference y to store 13 in its (shared) pointee
}
}
ОНОВЛЕННЯ: відповідно до пропозицій у коментарях, слід зазначити, що C має арифметику вказівника. Однак у нас цього немає на Java.
У Java є вказівники. Кожен раз, коли ви створюєте об’єкт на Java, ви фактично створюєте вказівник на об’єкт; тоді цей покажчик може бути встановлений на інший об'єкт або на null
, і початковий об’єкт все ще буде існувати (очікується збір сміття).
Те, що ви не можете зробити на Java, є арифметикою вказівника. Ви не можете знецінити конкретну адресу пам'яті або збільшити покажчик.
Якщо ви дійсно хочете отримати низький рівень, єдиний спосіб зробити це за допомогою інтерфейсу Java Native ; і навіть тоді частина низького рівня повинна бути виконана в C або C ++.
Оскільки у Java немає типів даних вказівника, використовувати вказівники в Java неможливо. Навіть нечисленні експерти не зможуть використовувати покажчики в java.
Дивіться також останній пункт у: Мовне середовище Java
У Java є вказівники, але ви не можете ними маніпулювати так, як ви можете в C ++ або C. Коли ви передаєте об'єкт, ви передаєте вказівник на цей об’єкт, але не в тому ж сенсі, що в C ++. Цей об'єкт не може бути відмежований. Якщо ви встановите його значення за допомогою вбудованих аксесуарів, вони зміняться, оскільки Java знає своє місцезнаходження в пам'яті через вказівник. Але вказівник незмінний. Коли ви намагаєтесь встановити вказівник на нове місце, ви замість цього отримаєте новий локальний об'єкт з тим же ім'ям, що й інший. Оригінальний об’єкт не змінюється. Ось коротка програма для демонстрації різниці.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
System.out.println("Expected # = 0 1 2 2 1");
Cat c = new Cat();
c.setClaws(0);
System.out.println("Initial value is " + c.getClaws());
// prints 0 obviously
clawsAreOne(c);
System.out.println("Accessor changes value to " + c.getClaws());
// prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
makeNewCat(c);
System.out.println("Final value is " + c.getClaws());
// prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
}
public static void clawsAreOne(Cat kitty) {
kitty.setClaws(1);
}
public static void makeNewCat(Cat kitty) {
Cat kitten = new Cat();
kitten.setClaws(2);
kitty = kitten;
System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
//Prints 2. the value pointed to by 'kitten' is 2
System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
//Prints 2. The local copy is being used within the scope of this method.
}
}
class Cat {
private int claws;
public void setClaws(int i) {
claws = i;
}
public int getClaws() {
return claws;
}
}
Це можна запустити на Ideone.com.
У Java немає вказівників, як на C, але вона дозволяє створювати нові об'єкти на купі, на які "посилаються" змінні. Відсутність покажчиків полягає в тому, що вони не дозволяють програмам Java незаконно посилатися на місця пам'яті, а також дозволяє автоматично збирати сміття віртуальною машиною Java.
Ви можете використовувати адреси та покажчики за допомогою класу Unsafe. Однак, як випливає з назви, ці методи є UNSAFE і взагалі погана ідея. Неправильне використання може призвести до випадкового вмирання вашого JVM (фактично така ж проблема отримати неправильне використання покажчиків у C / C ++)
Хоча ви можете звикнути до покажчиків і вважаєте, що вони вам потрібні (оскільки ви не знаєте, як кодувати інший спосіб), ви виявите, що цього не зробите, і вам буде краще для цього.
Технічно всі об’єкти Java є покажчиками. Усі примітивні типи є значеннями. Немає можливості вручну керувати цими вказівниками. Java просто внутрішньо використовує пропускний посилання.
Не дуже, ні.
У Java немає покажчиків. Якби ви насправді хотіли, можете спробувати наслідувати їх, будуючи навколо себе щось на зразок відображення, але це матиме всю складність покажчиків, не маючи жодної переваги .
У Java немає покажчиків, оскільки вони не потребують. Які відповіді ви сподівались на це питання, тобто глибоко в глибині душі ви сподівалися, що зможете їх використати для чогось чи це просто цікавість?
Усі об'єкти в Java передаються функціям шляхом копії, крім примітивів.
Фактично це означає, що ви надсилаєте копію вказівника на оригінальний об'єкт, а не копію самого об'єкта.
Залиште коментар, якщо ви хочете, щоб приклад зрозумів це.
swap
Java функцію, яка замінить два об'єкти.
Як казали інші, коротка відповідь - «Ні».
Звичайно, ви можете написати код JNI, який грає з покажчиками Java. Залежно від того, що ви намагаєтеся досягти, можливо, це десь потрапить у вас, а може, і не буде.
Ви завжди можете імітувати пункти, створюючи масив та працюючи з індексами в масиві. Знову ж таки, залежно від того, що ви намагаєтеся досягти, це може бути чи не корисно.
з книги під назвою Decompiling Android від Годфрі Нолана
Безпека диктує, що покажчики не використовуються на Java, тому хакери не можуть вийти з програми та в операційну систему. Жодні покажчики не означають, що щось інше ---- у цьому випадку JVM ---- повинен подбати про розподілення та звільнення пам'яті. Витоки пам’яті також повинні стати минулим, або так іде теорія. Деякі програми, написані на C і C ++, відомі тим, що протікає пам'ять, як сито, оскільки програмісти не звертають уваги на звільнення небажаної пам’яті у відповідний час — не те, що хтось, хто читає це, був би винним у такому гріху. Збір сміття також повинен зробити програмістів більш продуктивними, з тим менше часу витрачається на налагодження проблем з пам'яттю.
Ви можете мати вказівники і для літералів. Ви повинні їх реалізувати самостійно. Це досить базово для експертів;). Використовуйте масив int / object / long / byte та voila, який ви маєте основи для реалізації покажчиків. Тепер будь-яке значення int може бути вказівником на цей масив int []. Ви можете збільшити покажчик, ви можете декрементувати вказівник, ви можете помножити покажчик. У вас дійсно є вказівна арифметика! Це єдиний спосіб реалізувати 1000 класів атрибутів int та створити загальний метод, який застосовується до всіх атрибутів. Ви також можете використовувати байт [] масив замість int []
Однак я хочу, щоб Java дозволила вам передавати буквальні значення за посиланням. Щось уздовж рядків
//(* telling you it is a pointer)
public void myMethod(int* intValue);
Усі об'єкти java є вказівниками, тому що змінна, яка містить адресу, називається покажчиком, а об'єкт утримує address.so об'єктом є змінною вказівника.